fbi-2.10/0000755000175000017500000000000012506525033010325 5ustar jmmjmmfbi-2.10/backup/0000755000175000017500000000000012506525033011572 5ustar jmmjmmfbi-2.10/backup/Ida-de0000644000175000017500000001424212506525033012603 0ustar jmmjmm ! ---------------------------------------------------------------------------- ! some standard motif stuff [i18] *.cancelLabelString: Abbrechen *.XmFileSelectionBox.dirListLabelString: Verzeichnisse *.XmFileSelectionBox.fileListLabelString: Dateien *.XmFileSelectionBox.selectionLabelString: Auswahl ! ---------------------------------------------------------------------------- ! strings [i18] Ida.aboutbox_popup.title: ber ida Ida*aboutbox_popup*messageString: \ ida - image viewer & editor \n\ \n\ (c) 2001,02 Gerd Hoffmann Ida.noundobox_popup.title: Nicht verfgbar Ida*noundobox_popup*messageString: \ Es kann nur der letzte Arbeitsschritt\n\ rckgnig gemacht werden. Ida.errbox_popup.title: Fehler Ida.load_popup.title: Datei ffnen Ida.save_popup.title: Datei speichern Ida.save_popup*format.labelString: Dateiformat: Ida.print_popup.title: Datei drucken Ida.print_popup*selectionLabelString: Kommando Ida.print_popup*textString: lpr Ida*jpeg_popup.title: JPEG Einstellungen Ida*jpeg_popup*selectionLabelString: Bildqualitt (0 ... 100) Ida*ps_popup.title: PostScript Einstellungen Ida*ps_popup*paper.labelString: Papier: Ida*ps_popup*ori.labelString: Format: Ida*ps_popup*oriM.portrait.labelString: Hochformat Ida*ps_popup*oriM.landscape.labelString: Querformat Ida.gamma_popup.title: Gammakorrektur Ida.gamma_popup*selectionLabelString: Gamma Wert Ida.bright_popup.title: Helligkeit ndern Ida.bright_popup*selectionLabelString: Helligkeit Ida.contrast_popup.title: Kontrast ndern Ida.contrast_popup*selectionLabelString: Kontrast Ida.rotate_popup.title: Bild drehen Ida.rotate_popup*selectionLabelString: Drehwinkel Ida.sharpe_popup.title: Bild schrfen Ida.sharpe_popup*selectionLabelString: Wert Ida.resize_popup.title: Bild skalieren Ida.resize_popup*lx.labelString: Breite (Pixel) Ida.resize_popup*ly.labelString: Hhe (Pixel) Ida.resize_popup*lr.labelString: Auflsung (dpi) Ida.resize_popup*lock.labelString: Seitenverhltnis beibehalten Ida.resize_popup*size.labelString: Gre ndern Ida.resize_popup*res.labelString: Auflsung ndern Ida.resize_popup*phys.labelString: Bildgre Ida.color_popup.title: Edit colors Ida.color_popup*hist.labelString: Histograms Ida.color_popup*map.labelString: Maps Ida.color_popup*lock.labelString: Same values for all channels Ida.color_popup*vals.labelString: Show values for channel: Ida.color_popup*valsM.red.labelString: red Ida.color_popup*valsM.green.labelString: green Ida.color_popup*valsM.blue.labelString: blue Ida.color_popup*in.label.labelString: Input range: Ida.color_popup*out.label.labelString: Output range: Ida.color_popup*gamma.label.labelString: Gamma: Ida.color_popup*white.labelString: Weipunkt setzen ctrl.title: ida controls ctrl.form.status.labelString: fixme ctrl*bar.file.labelString: Datei ctrl*bar.file.mnemonic: D ctrl*bar*load.labelString: ffnen ... ctrl*bar*load.mnemonic: Odiaeresis ctrl*bar*save.labelString: Speichern ... ctrl*bar*save.mnemonic: S ctrl*bar*browse.labelString: Datei Browser ... ctrl*bar*scan.labelString: Scannen ctrl*bar*print.labelString: Drucken ... ctrl*bar*quit.labelString: Beenden ctrl*bar*quit.mnemonic: B ctrl*bar.edit.labelString: Bearbeiten ctrl*bar.edit.mnemonic: B ctrl*bar*undo.labelString: Rckgnig ctrl*bar*undo.mnemonic: udiaeresis ctrl*bar*copy.labelString: Kopieren ctrl*bar*paste.labelString: Einfgen ctrl*bar*flipv.labelString: Vertikal spiegeln ctrl*bar*flipv.mnemonic: V ctrl*bar*fliph.labelString: Horizontal spiegeln ctrl*bar*fliph.mnemonic: H ctrl*bar*rotcw.labelString: Drehen im Uhrzeigersinn ctrl*bar*rotccw.labelString: Drehen gegen den Uhrzeigersinn ctrl*bar*invert.labelString: Invertieren ctrl*bar*invert.mnemonic: I ctrl*bar*crop.labelString: Crop ctrl*bar*crop.mnemonic: C ctrl*bar*acrop.labelString: Autocrop ctrl*bar*acrop.mnemonic: A ctrl*bar*scale.labelString: Skalieren ... ctrl*bar*scale.mnemonic: S ctrl*bar*rotany.labelString: Drehen ... ctrl*bar.op.labelString: Filter ctrl*bar.op.mnemonic: F ctrl*bar*gamma.labelString: Gamma ... ctrl*bar*gamma.mnemonic: G ctrl*bar*bright.labelString: Helligheit ... ctrl*bar*contr.labelString: Kontrast ... ctrl*bar*color.labelString: Farben bearbeiten ctrl*bar*color.mnemonic: e ctrl*bar*gray.labelString: In Graustufen wandeln ctrl*bar*blur.labelString: Weich zeichnen ctrl*bar*sharpe.labelString: Schrfen ... ctrl*bar*edge.labelString: Kanten finden ctrl*bar*emboss.labelString: Schattenri ctrl*bar.view.labelString: Ansicht ctrl*bar.view.mnemonic: A ctrl*bar*prev.labelString: Vorherige Datei ctrl*bar*next.labelString: Nchste Datei ctrl*bar*prevpage.labelString: Vorherige Seite ctrl*bar*nextpage.labelString: Nchste Seite ctrl*bar*zoomin.labelString: Vergrern ctrl*bar*zoomout.labelString: Verkleinern ctrl*bar.opt.labelString: Einstellungen ctrl*bar.view.mnemonic: E ctrl*bar*pcd.labelString: PhotoCD Auflsung ctrl*bar.help.labelString: Hilfe ctrl*bar.help.mnemonic: H ctrl*bar*man.labelString: Manual page ... ctrl*bar*man.mnemonic: M ctrl*bar*about.labelString: ber ... ctrl*bar*about.mnemonic: Udiaeresis ctrl*tool.prev.toolTipString: vorherige Datei ctrl*tool.next.toolTipString: nchste Datei ctrl*tool.zoomin.toolTipString: Vergrern ctrl*tool.zoomout.toolTipString: Verkleinern ctrl*tool.flipv.toolTipString: Vertikal spiegeln ctrl*tool.fliph.toolTipString: Horizontal spiegeln ctrl*tool.rotccw.toolTipString: Drehen gegen Uhrzeigersinn ctrl*tool.rotcw.toolTipString: Drehen im Uhrzeigersinn ctrl*tool.exit.toolTipString: Beenden browser*bar.file.labelString: Datei browser*bar.file.mnemonic: D browser*bar*close.labelString: Fenster schlieen browser*bar.view.labelString: Ansicht browser*bar.view.mnemonic: A browser*bar*filter.labelString: Filtern ... browser*bar*freset.labelString: Filter aufheben browser.filter_popup.title: Filter browser.filter_popup*selectionLabelString: pattern? browser*menu.copy.labelString: Kopieren (ins Clipboard) browser*menu.rotcw.labelString: Drehen im Uhrzeigersinn browser*menu.rotccw.labelString: Drehen gegen den Uhrzeigersinn Ida.man_popup.title: Manual page Ida.man_popup*okLabelString: Fenster schlieen Ida.man_popup*label.labelString: Einen Moment bitte ... fbi-2.10/backup/Ida-default0000644000175000017500000001370612506525033013643 0ustar jmmjmm! ---------------------------------------------------------------------------- ! strings [i18] Ida.aboutbox_popup.title: About ida Ida*aboutbox_popup*messageString: \ ida - image viewer & editor \n\ \n\ (c) 2001,02 Gerd Hoffmann Ida.noundobox_popup.title: No undo Ida*noundobox_popup*messageString: \ No undo info available, sorry. \n\ You can undo the last step only. Ida.errbox_popup.title: Errors Ida.load_popup.title: Load File Ida.save_popup.title: Save File Ida.save_popup*format.labelString: Image format: Ida.print_popup.title: Print File Ida.print_popup*selectionLabelString: Print command Ida.print_popup*textString: lpr Ida*jpeg_popup.title: JPEG Options Ida*jpeg_popup*selectionLabelString: Image quality (0 ... 100) Ida*ps_popup.title: PostScript Options Ida*ps_popup*paper.labelString: Paper size: Ida*ps_popup*ori.labelString: Orientation: Ida.gamma_popup.title: Gamma correction Ida.gamma_popup*selectionLabelString: Gamma value Ida.bright_popup.title: Adjust bright Ida.bright_popup*selectionLabelString: Bright Ida.contrast_popup.title: Adjust contrast Ida.contrast_popup*selectionLabelString: Contrast Ida.rotate_popup.title: Rotate image Ida.rotate_popup*selectionLabelString: angle Ida.sharpe_popup.title: Sharpe image Ida.sharpe_popup*selectionLabelString: value Ida.resize_popup.title: Scale image Ida.resize_popup*lx.labelString: Width (pixels) Ida.resize_popup*ly.labelString: Height (pixels) Ida.resize_popup*lr.labelString: Resolution (dpi) Ida.resize_popup*lock.labelString: Keep aspect ratio Ida.resize_popup*size.labelString: Change size Ida.resize_popup*res.labelString: Change resolution Ida.resize_popup*phys.labelString: Image size Ida.color_popup.title: Edit colors Ida.color_popup*hist.labelString: Histograms Ida.color_popup*map.labelString: Maps Ida.color_popup*lock.labelString: Same values for all channels Ida.color_popup*vals.labelString: Show values for channel: Ida.color_popup*valsM.red.labelString: red Ida.color_popup*valsM.green.labelString: green Ida.color_popup*valsM.blue.labelString: blue Ida.color_popup*in.label.labelString: Input range: Ida.color_popup*out.label.labelString: Output range: Ida.color_popup*gamma.label.labelString: Gamma: !Ida.color_popup*white.labelString: FIXME ctrl.title: ida controls ctrl.form.status.labelString: fixme ctrl*bar.file.labelString: File ctrl*bar.file.mnemonic: F ctrl*bar*load.labelString: Load image ... ctrl*bar*load.mnemonic: L ctrl*bar*save.labelString: Save image ... ctrl*bar*save.mnemonic: S ctrl*bar*browse.labelString: File browser ... ctrl*bar*filelist.labelString: File list ... ctrl*bar*scan.labelString: Scan ctrl*bar*print.labelString: Print ... ctrl*bar*print.mnemonic: P ctrl*bar*quit.labelString: Quit ctrl*bar*quit.mnemonic: Q ctrl*bar.edit.labelString: Edit ctrl*bar.edit.mnemonic: E ctrl*bar*undo.labelString: Undo last operation ctrl*bar*undo.mnemonic: U ctrl*bar*copy.labelString: Copy ctrl*bar*paste.labelString: Paste ctrl*bar*flipv.labelString: Flip vertical ctrl*bar*flipv.mnemonic: v ctrl*bar*fliph.labelString: Flip horizontal ctrl*bar*fliph.mnemonic: h ctrl*bar*rotcw.labelString: Turn clockwise ctrl*bar*rotcw.mnemonic: T ctrl*bar*rotccw.labelString: Turn counter clockwise ctrl*bar*invert.labelString: Invert ctrl*bar*invert.mnemonic: I ctrl*bar*crop.labelString: Crop ctrl*bar*crop.mnemonic: C ctrl*bar*acrop.labelString: Autocrop ctrl*bar*acrop.mnemonic: A ctrl*bar*scale.labelString: Scale ... ctrl*bar*scale.mnemonic: S ctrl*bar*rotany.labelString: Rotate ... ctrl*bar.op.labelString: Filters ctrl*bar.op.mnemonic: F ctrl*bar*gamma.labelString: Gamma ... ctrl*bar*gamma.mnemonic: G ctrl*bar*bright.labelString: Bright ... ctrl*bar*bright.mnemonic: B ctrl*bar*contr.labelString: Contrast ... ctrl*bar*contr.mnemonic: C ctrl*bar*color.labelString: Edit colors ... ctrl*bar*color.mnemonic: E ctrl*bar*gray.labelString: Grayscale ctrl*bar*blur.labelString: Blur ctrl*bar*sharpe.labelString: Sharpe ... ctrl*bar*edge.labelString: Edge detect ctrl*bar*emboss.labelString: Emboss ctrl*bar.view.labelString: View ctrl*bar.view.mnemonic: V ctrl*bar*prev.labelString: previous file ctrl*bar*next.labelString: next file ctrl*bar*prevpage.labelString: previous page ctrl*bar*nextpage.labelString: next page ctrl*bar*zoomin.labelString: Zoom in ctrl*bar*zoomout.labelString: Zoom out ctrl*bar.opt.labelString: Options ctrl*bar.view.mnemonic: O ctrl*bar*pcd.labelString: PhotoCD resolution ctrl*bar.help.labelString: Help ctrl*bar.help.mnemonic: H ctrl*bar*man.labelString: Manual page ... ctrl*bar*man.mnemonic: M ctrl*bar*about.labelString: About ... ctrl*bar*about.mnemonic: A ctrl*tool.prev.toolTipString: previous file ctrl*tool.next.toolTipString: next file ctrl*tool.zoomin.toolTipString: zoom in ctrl*tool.zoomout.toolTipString: zoom out ctrl*tool.flipv.toolTipString: flip vertical ctrl*tool.fliph.toolTipString: flip horizontal ctrl*tool.rotccw.toolTipString: turn counter clockwise ctrl*tool.rotcw.toolTipString: turn clockwise ctrl*tool.exit.toolTipString: quit browser.filter_popup.title: Filter browser.filter_popup*selectionLabelString: pattern? Ida.man_popup.title: Manual page Ida.man_popup*okLabelString: close window Ida.man_popup*label.labelString: please wait ... *cbar.file.labelString: File *cbar.file.mnemonic: F *cbar*new.labelString: New list *cbar*new.mnemonic: N *cbar*load.labelString: Load list ... *cbar*load.mnemonic: L *cbar*save.labelString: Save list *cbar*save.mnemonic: S *cbar*saveas.labelString: Save list as ... *cbar*saveas.mnemonic: a *cbar*close.labelString: Close window *cbar.edit.labelString: Edit *cbar.edit.mnemonic: E *cbar*copy.labelString: Copy *cbar*paste.labelString: Paste *cbar*del.labelString: Delete *cbar.view.labelString: View *cbar.view.mnemonic: V *cbar*spatial.labelString: Large Icons *cbar*details.labelString: Details *cbar*filter.labelString: Filter ... *cbar*freset.labelString: Reset filter fbi-2.10/backup/Ida-fixed0000644000175000017500000003753012506525033013317 0ustar jmmjmm ! ---------------------------------------------------------------------------- ! fonts *renderTable: small *renderTable.fontType: FONT_IS_FONTSET *renderTable.fontName: \ -*-bitstream vera sans-medium-r-normal-*-*-140-*-*-p-*-iso8859-1, \ -*-bitstream vera sans-medium-r-normal-*-*-140-*-*-p-*-iso8859-15, \ -microsoft-tahoma-medium-r-normal-*-*-140-*-*-p-*-iso8859-*, \ -adobe-helvetica-medium-r-normal-*-*-140-*-*-p-*-iso8859-*, \ -cronyx-helvetica-medium-r-normal-*-*-140-*-*-p-*-koi8-r, \ -*-lucida-medium-r-normal-*-*-140-*-*-p-*-iso8859-*, \ -gnu-unifont-medium-r-normal-*-*-160-*-*-*-*-*-*, \ -*-*-medium-r-normal-*-*-140-*-*-p-*-*-*, \ -*-*-medium-r-normal-*-*-160-*-*-p-*-*-*, \ -*-*-*-*-*-*-*-140-*-*-*-*-*-*, \ -*-*-*-*-*-*-*-160-*-*-*-*-*-*, * *renderTable.small.fontType: FONT_IS_FONTSET *renderTable.small.fontName: \ -*-bitstream vera sans-medium-r-normal-*-*-100-*-*-p-*-iso8859-1, \ -*-bitstream vera sans-medium-r-normal-*-*-100-*-*-p-*-iso8859-15, \ -microsoft-tahoma-medium-r-normal-*-*-100-*-*-p-*-iso8859-*, \ -adobe-helvetica-medium-r-normal-*-*-100-*-*-p-*-iso8859-*, \ -cronyx-helvetica-medium-r-normal-*-*-100-*-*-p-*-koi8-r, \ -*-lucida-medium-r-normal-*-*-100-*-*-p-*-iso8859-*, \ -*-*-medium-r-normal-*-*-100-*-*-p-*-*-*, \ -*-*-medium-r-normal-*-*-120-*-*-p-*-*-*, \ -*-*-*-*-*-*-*-100-*-*-*-*-*-*, \ -*-*-*-*-*-*-*-120-*-*-*-*-*-*, * *XmTextField.renderTable: *XmTextField.renderTable.fontType: FONT_IS_FONTSET *XmTextField.renderTable.fontName: \ -*-bitstream vera sans mono-medium-r-normal-*-*-140-*-*-*-*-iso8859-1, \ -*-bitstream vera sans mono-medium-r-normal-*-*-140-*-*-*-*-iso8859-15, \ -monotype-andale mono-medium-r-normal-*-*-140-*-*-*-*-iso8859-*, \ -adobe-courier-medium-r-normal-*-*-140-*-*-m-*-iso8859-*, \ -cronyx-courier-medium-r-normal-*-*-140-*-*-m-*-koi8-r, \ -*-lucidatypewriter-medium-r-normal-*-*-140-*-*-m-*-iso8859-*, \ -*-*-medium-r-normal-*-*-140-*-*-m-*-*-*, \ -*-*-medium-r-normal-*-*-160-*-*-m-*-*-*, \ -*-*-*-*-*-*-*-140-*-*-*-*-*-*, \ -*-*-*-*-*-*-*-160-*-*-*-*-*-*, * !*.shadowThickness: 2 !*.highlightThickness: 1 ! ---------------------------------------------------------------------------- ! image window Ida.geometry: 75x50 !Ida.winGravity: static Ida.view*translations: #override \ space: Next() \n\ osfDelete: Prev() \n\ osfBackSpace: Prev() \n\ Page_Down: NextPage() \n\ Page_Up: PrevPage() \n\ KP_Add: Zoom(inc) \n\ KP_Subtract: Zoom(dec) \n\ : Ipc(drag) \n\ : Popup(control) \n\ \ G: Gamma() \n\ F: Browser() \n\ L: Filelist() \n\ CtrlV: Ipc(paste) \n\ AltV: Ipc(paste) \n\ CtrlC: Ipc(copy) \n\ AltC: Ipc(copy) \n\ \ CtrlP: Print() \n\ CtrlL: Load() \n\ CtrlS: Save() \n\ AltS: Sharpe() \n\ ~Alt ~CtrlS: Resize() \n\ plus: Zoom(inc) \n\ minus: Zoom(dec) \n\ U: Undo() \n\ ~Alt ~CtrlC: Filter(crop) \n\ ~Alt ~CtrlV: Filter(flip-vert) \n\ H: Filter(flip-horz) \n\ ~Alt ~ShiftT: Filter(rotate-cw) \n\ ShiftT: Filter(rotate-ccw) \n\ AltT: Rotate() \n\ I: Filter(invert) \n\ ~AltE: Color() \n\ AltE: F3x3(-1,-1,-1,-1,8,-1,-1,-1,-1) \n\ AltB: F3x3(1,1,1,1,1,1,1,1,1, 1,9) \n\ AltM: F3x3(1,0,0,0,0,0,0,0,-1, 0,0,128) \n\ osfHelp: Man(ida) \n\ Q: Exit() Ida.view.VertScrollBar.accelerators: #override \ : IncrementUpOrLeft(Up) \n\ : IncrementDownOrRight(Down)\n\ ~CtrlosfUp: IncrementUpOrLeft(Up) \n\ ~CtrlosfDown: IncrementDownOrRight(Down)\n\ CtrlosfUp: PageUpOrLeft(Up) \n\ CtrlosfDown: PageDownOrRight(Down) Ida.view.HorScrollBar.accelerators: #override \ ~CtrlosfLeft: IncrementUpOrLeft(Left) \n\ ~CtrlosfRight: IncrementDownOrRight(Right)\n\ CtrlosfLeft: PageUpOrLeft(Left) \n\ CtrlosfRight: PageDownOrRight(Right) Ida.view.shadowThickness: 1 Ida.view.scrollingPolicy: AUTOMATIC Ida.view.scrollBarPlacement: BOTTOM_RIGHT Ida.view.scrolledWindowChildType: SCROLL_VERT Ida.view*image.backgroundPixmap: none Ida.view*image.borderWidth: 0 Ida.view*image.highlightThickness: 1 Ida.view*image.highlightColor: red Ida.aboutbox_popup.deleteResponse: DESTROY Ida.sorrybox_popup.deleteResponse: DESTROY Ida.noundobox_popup.deleteResponse: DESTROY ! ---------------------------------------------------------------------------- ! dialog boxes Ida.XmDialogShell.deleteResponse: DESTROY Ida.XmDialogShell*scale.orientation: HORIZONTAL Ida.XmDialogShell*scale.showValue: True Ida.errbox_popup.deleteResponse: UNMAP Ida.load_popup.deleteResponse: UNMAP Ida.save_popup*deleteResponse: UNMAP Ida.save_popup*dialogStyle: DIALOG_PRIMARY_APPLICATION_MODAL Ida.print_popup*deleteResponse: UNMAP Ida.print_popup*dialogStyle: DIALOG_PRIMARY_APPLICATION_MODAL Ida*ps_popup*rc1.orientation: HORIZONTAL Ida*ps_popup*draw.borderWidth: 1 Ida*ps_popup*draw.background: white Ida*ps_popup*draw.resizePolicy: RESIZE_NONE Ida*ps_popup*scale.titleString: Scaling Ida*ps_popup*scale.minimum: 10 Ida*ps_popup*scale.maximum: 1000 Ida*ps_popup*scale.decimalPoints: 1 Ida.gamma_popup*scale.minimum: 20 Ida.gamma_popup*scale.maximum: 500 Ida.gamma_popup*scale.decimalPoints: 2 Ida.bright_popup*scale.minimum: -256 Ida.bright_popup*scale.maximum: 256 Ida.contrast_popup*scale.minimum: -128 Ida.contrast_popup*scale.maximum: 512 Ida.rotate_popup*scale.minimum: -180 Ida.rotate_popup*scale.maximum: 180 Ida.sharpe_popup*scale.minimum: 0 Ida.sharpe_popup*scale.maximum: 100 Ida.resize_popup.deleteResponse: DESTROY Ida.resize_popup*rc.adjustMargin: false Ida.resize_popup*rc.rc.orientation: HORIZONTAL Ida.resize_popup*rc.rc.?.indicatorType: ONE_OF_MANY ! ---------------------------------------------------------------------------- ! edit colors dialog Ida.color_popup.deleteResponse: DESTROY Ida.color_popup*XmForm*leftOffset: 10 Ida.color_popup*XmForm*rightOffset: 10 Ida.color_popup*XmForm*topOffset: 10 Ida.color_popup*XmForm*bottomOffset: 10 Ida.color_popup*XmForm*leftAttachment: ATTACH_WIDGET Ida.color_popup*XmForm*topAttachment: ATTACH_WIDGET Ida.color_popup*XmForm.sep.rightAttachment: ATTACH_FORM Ida.color_popup*XmForm.XmRowColumn.rightAttachment: ATTACH_FORM Ida.color_popup*XmForm.XmRowColumn.orientation: HORIZONTAL Ida.color_popup*XmText.columns: 5 Ida.color_popup*XmDrawingArea.background: white Ida.color_popup*XmDrawingArea.borderWidth: 1 Ida.color_popup*XmDrawingArea.borderColor: black Ida.color_popup*hred.topWidget: hist Ida.color_popup*hgreen.topWidget: hred Ida.color_popup*hblue.topWidget: hgreen Ida.color_popup*map.leftWidget: hred Ida.color_popup*mred.topWidget: hist Ida.color_popup*mred.leftWidget: hred Ida.color_popup*mred.rightAttachment: ATTACH_FORM Ida.color_popup*mgreen.topWidget: mred Ida.color_popup*mgreen.leftWidget: hgreen Ida.color_popup*mgreen.rightAttachment: ATTACH_FORM Ida.color_popup*mblue.topWidget: mgreen Ida.color_popup*mblue.leftWidget: hblue Ida.color_popup*mblue.rightAttachment: ATTACH_FORM Ida.color_popup*lock.topWidget: hblue Ida.color_popup*vals.topWidget: lock Ida.color_popup*in.topWidget: vals Ida.color_popup*out.topWidget: in Ida.color_popup*gamma.topWidget: out Ida.color_popup*pick.topWidget: gamma ! ---------------------------------------------------------------------------- ! control ctrl*XmMenuShell.XmRowColumn.tearOffModel: TEAR_OFF_ENABLED ctrl*tool.orientation: HORIZONTAL ctrl*tool.XmPushButton.shadowThickness: 1 ctrl.toolTipEnable: 1 ctrl.toolTipPostDelay: 2000 ctrl.toolTipPostDuration: 5000 ctrl*TipLabel.foreground: black ctrl*TipLabel.background: lightyellow ctrl*TipShell.borderWidth: 1 ctrl*TipShell.borderColor: black ctrl*tool.XmSeparator.orientation: VERTICAL ctrl*tool.XmSeparator.width: 12 ctrl*tool.XmSeparator.margin: 3 ctrl*tool.XmPushButton.labelType: PIXMAP ctrl*tool.prev.labelPixmap: prev ctrl*tool.next.labelPixmap: next ctrl*tool.zoomin.labelPixmap: zoomin ctrl*tool.zoomout.labelPixmap: zoomout ctrl*tool.flipv.labelPixmap: flipv ctrl*tool.fliph.labelPixmap: fliph ctrl*tool.rotccw.labelPixmap: rotccw ctrl*tool.rotcw.labelPixmap: rotcw ctrl*tool.exit.labelPixmap: exit ctrl.form*list.visibleItemCount: 12 ctrl.form*list.translations: #override \ space: Next() \n\ osfDelete: Prev() \n\ osfBackSpace: Prev() \n\ KP_Add: Zoom(inc) \n\ KP_Subtract: Zoom(dec) ctrl*bar*load.acceleratorText: Ctrl+L ctrl*bar*load.accelerator: CtrlL ctrl*bar*save.acceleratorText: Ctrl+S ctrl*bar*save.accelerator: CtrlS ctrl*bar*browse.acceleratorText: F ctrl*bar*browse.accelerator: F ctrl*bar*filelist.acceleratorText: L ctrl*bar*filelist.accelerator: L ctrl*bar*print.acceleratorText: Ctrl+P ctrl*bar*print.accelerator: CtrlP ctrl*bar*quit.acceleratorText: Q ctrl*bar*quit.accelerator: Q ctrl*bar*undo.acceleratorText: U ctrl*bar*undo.accelerator: U ctrl*bar*copy.acceleratorText: Ctrl+C ctrl*bar*copy.accelerator: CtrlC ctrl*bar*paste.acceleratorText: Ctrl+V ctrl*bar*paste.accelerator: CtrlV ctrl*bar*flipv.acceleratorText: V ctrl*bar*flipv.accelerator: V ctrl*bar*fliph.acceleratorText: H ctrl*bar*fliph.accelerator: H ctrl*bar*rotcw.acceleratorText: T ctrl*bar*rotcw.accelerator: ~Meta ~ShiftT ctrl*bar*rotccw.acceleratorText: Shift+T ctrl*bar*rotccw.accelerator: ShiftT ctrl*bar*invert.acceleratorText: I ctrl*bar*invert.accelerator: I ctrl*bar*crop.acceleratorText: C ctrl*bar*crop.accelerator: C ctrl*bar*scale.acceleratorText: S ctrl*bar*scale.accelerator: ~CtrlS ctrl*bar*rotany.acceleratorText: Alt+T ctrl*bar*rotany.accelerator: AltT ctrl*bar*gamma.acceleratorText: G ctrl*bar*gamma.accelerator: G ctrl*bar*color.acceleratorText: E ctrl*bar*color.accelerator: ~AltE ctrl*bar*blur.acceleratorText: Alt+B ctrl*bar*blur.accelerator: AltB ctrl*bar*sharpe.acceleratorText: Alt+S ctrl*bar*sharpe.accelerator: AltS ctrl*bar*edge.acceleratorText: Alt+E ctrl*bar*edge.accelerator: AltE ctrl*bar*emboss.acceleratorText: Alt+M ctrl*bar*emboss.accelerator: Altm ctrl*bar*prev.acceleratorText: backspace !ctrl*bar*prev.accelerator: Backspace ctrl*bar*next.acceleratorText: space !ctrl*bar*next.accelerator: space ctrl*bar*prevpage.acceleratorText: PageUp !ctrl*bar*prevpage.accelerator: osfPageUp ctrl*bar*nextpage.acceleratorText: PageDown !ctrl*bar*nextpage.accelerator: osfPageDown ctrl*bar*zoomin.acceleratorText: plus ctrl*bar*zoomin.accelerator: plus ctrl*bar*zoomout.acceleratorText: minus ctrl*bar*zoomout.accelerator: minus ctrl*bar*pcdM.1.labelString: 192 x 128 ctrl*bar*pcdM.2.labelString: 384 x 256 ctrl*bar*pcdM.3.labelString: 768 x 512 ctrl*bar*pcdM.4.labelString: 1536 x 1024 ctrl*bar*pcdM.5.labelString: 3072 x 2048 ctrl*bar*man.acceleratorText: F1 ctrl*bar*man.accelerator: F1 ctrl.form.*.leftAttachment: ATTACH_FORM ctrl.form.*.rightAttachment: ATTACH_FORM ctrl.form.tool.topAttachment: ATTACH_WIDGET ctrl.form.tool.topWidget: bar ctrl.form.listSW.topAttachment: ATTACH_WIDGET ctrl.form.listSW.topWidget: tool ctrl.form.listSW.bottomAttachment: ATTACH_WIDGET ctrl.form.listSW.bottomWidget: status ctrl.form.listSW.width: 320 ctrl.form.listSW.height: 240 ctrl.form.status.bottomAttachment: ATTACH_FORM ctrl.form.status.alignment: ALIGNMENT_BEGINNING ! ---------------------------------------------------------------------------- ! man page renderer Ida.man_popup.deleteResponse: DESTROY Ida.man_popup*view.width: 500 Ida.man_popup*view.height: 600 Ida.man_popup*view.scrollingPolicy: AUTOMATIC Ida.man_popup*view.scrollBarPlacement: BOTTOM_RIGHT Ida.man_popup*label.alignment: ALIGNMENT_BEGINNING Ida.man_popup*label.marginWidth: 5 Ida.man_popup*label.marginHeight: 5 Ida.man_popup*label.renderTable: bold,underline Ida.man_popup*label.renderTable.fontType: FONT_IS_FONTSET Ida.man_popup*label.renderTable.fontName: \ -*-fixed-medium-r-normal--13-*-*-*-*-*-iso8859-*, \ -*-fixed-medium-r-normal-ja-13-*-*-*-*-*-iso10646-1, \ -gnu-unifont-medium-r-normal--16-*-*-*-*-*-*-*,* Ida.man_popup*label.renderTable.bold.fontType: FONT_IS_FONTSET Ida.man_popup*label.renderTable.bold.fontName: \ -*-fixed-bold-r-normal--13-*-*-*-*-*-iso8859-*, \ -*-fixed-medium-r-normal-ja-13-*-*-*-*-*-iso10646-1, \ -gnu-unifont-bold-r-normal--16-*-*-*-*-*-*-*,* Ida.man_popup*label.renderTable.underline.underlineType: SINGLE_LINE ! ---------------------------------------------------------------------------- ! hex viewer Ida.hex_popup.deleteResponse: DESTROY Ida.hex_popup*view.width: 600 Ida.hex_popup*view.height: 600 Ida.hex_popup*view.scrollingPolicy: AUTOMATIC Ida.hex_popup*view.scrollBarPlacement: BOTTOM_RIGHT Ida.hex_popup*label.alignment: ALIGNMENT_BEGINNING Ida.hex_popup*label.marginWidth: 5 Ida.hex_popup*label.marginHeight: 5 Ida.hex_popup*label.renderTable: bold,underline Ida.hex_popup*label.renderTable.fontType: FONT_IS_FONTSET Ida.hex_popup*label.renderTable.fontName: \ -*-fixed-medium-r-normal--13-*-*-*-*-*-iso8859-*, \ -*-fixed-medium-r-normal-ja-13-*-*-*-*-*-iso10646-1, \ -gnu-unifont-medium-r-normal--16-*-*-*-*-*-*-*,* Ida.hex_popup*label.renderTable.bold.fontType: FONT_IS_FONTSET Ida.hex_popup*label.renderTable.bold.fontName: \ -*-fixed-bold-r-normal--13-*-*-*-*-*-iso8859-*, \ -*-fixed-medium-r-normal-ja-13-*-*-*-*-*-iso10646-1, \ -gnu-unifont-bold-r-normal--16-*-*-*-*-*-*-*,* Ida.hex_popup*label.renderTable.underline.underlineType: SINGLE_LINE ! ---------------------------------------------------------------------------- ! file browser browser.geometry: 600x450 browser.form.?.leftAttachment: ATTACH_FORM browser.form.?.rightAttachment: ATTACH_FORM browser.form.scroll.topAttachment: ATTACH_WIDGET browser.form.scroll.topWidget: cbar browser.form.scroll.bottomAttachment: ATTACH_WIDGET browser.form.scroll.bottomWidget: status browser.form.status.bottomAttachment: ATTACH_FORM browser.form.status.alignment: ALIGNMENT_BEGINNING browser.form.scroll.scrollingPolicy: AUTOMATIC browser.form.scroll.scrollBarPlacement: BOTTOM_RIGHT browser.form.scroll.XmScrollBar.highlightThickness: 1 *container.outlineButtonPolicy: OUTLINE_BUTTON_ABSENT *container.spatialStyle: CELLS *container.spatialResizeModel: GROW_MINOR *container.spatialSnapModel: CENTER !*container.spatialIncludeModel: APPEND !*container.layoutDirection: LEFT_TO_RIGHT_TOP_TO_BOTTOM *container.background: gray85 *container.XmIconGadget.highlightColor: darkred *container.XmIconGadget.shadowThickness: 1 *cbar*close.acceleratorText: Q *cbar*close.accelerator: Q *cbar*copy.acceleratorText: Ctrl+C *cbar*copy.accelerator: CtrlC *cbar*paste.acceleratorText: Ctrl+V *cbar*paste.accelerator: CtrlV *cbar*filter.acceleratorText: F *cbar*filter.accelerator: F ! ---------------------------------------------------------------------------- ! file lists filelist.geometry: 300x400 filelist.form.?.leftAttachment: ATTACH_FORM filelist.form.?.rightAttachment: ATTACH_FORM filelist.form.scroll.topAttachment: ATTACH_WIDGET filelist.form.scroll.topWidget: cbar filelist.form.scroll.bottomAttachment: ATTACH_WIDGET filelist.form.scroll.bottomWidget: status filelist.form.status.bottomAttachment: ATTACH_FORM filelist.form.status.alignment: ALIGNMENT_BEGINNING filelist.form.scroll.scrollingPolicy: AUTOMATIC filelist.form.scroll.scrollBarPlacement: BOTTOM_RIGHT filelist.form.scroll.XmScrollBar.highlightThickness: 1 fbi-2.10/dither.c0000644000175000017500000001062712506525033011756 0ustar jmmjmm/* * ordered dither rotines * * stolen from The GIMP and trimmed for speed * */ #include #include "dither.h" #define DITHER_LEVEL 8 void (*dither_line)(unsigned char *, unsigned char *, int, int); static long red_mult, green_mult; static long red_dither[256]; static long green_dither[256]; static long blue_dither[256]; static long gray_dither[256]; typedef unsigned long vector[DITHER_LEVEL]; typedef vector matrix[DITHER_LEVEL]; #if DITHER_LEVEL == 8 #define DITHER_MASK 7 static matrix DM = { {0, 32, 8, 40, 2, 34, 10, 42}, {48, 16, 56, 24, 50, 18, 58, 26}, {12, 44, 4, 36, 14, 46, 6, 38}, {60, 28, 52, 20, 62, 30, 54, 22}, {3, 35, 11, 43, 1, 33, 9, 41}, {51, 19, 59, 27, 49, 17, 57, 25}, {15, 47, 7, 39, 13, 45, 5, 37}, {63, 31, 55, 23, 61, 29, 53, 21} }; #endif #if DITHER_LEVEL == 4 #define DITHER_MASK 3 static matrix DM = { {0, 8, 2, 10}, {12, 4, 14, 6}, {3, 11, 1, 9}, {15, 7, 13, 5} }; #endif void init_dither(int shades_r, int shades_g, int shades_b, int shades_gray) { int i, j; unsigned char low_shade, high_shade; unsigned short index; float red_colors_per_shade; float green_colors_per_shade; float blue_colors_per_shade; float gray_colors_per_shade; red_mult = shades_g * shades_b; green_mult = shades_b; red_colors_per_shade = 256.0 / (shades_r - 1); green_colors_per_shade = 256.0 / (shades_g - 1); blue_colors_per_shade = 256.0 / (shades_b - 1); gray_colors_per_shade = 256.0 / (shades_gray - 1); /* this avoids a shift when checking these values */ for (i = 0; i < DITHER_LEVEL; i++) for (j = 0; j < DITHER_LEVEL; j++) DM[i][j] *= 0x10000; /* setup arrays containing three bytes of information for red, green, & blue */ /* the arrays contain : * 1st byte: low end shade value * 2nd byte: high end shade value * 3rd & 4th bytes: ordered dither matrix index */ for (i = 0; i < 256; i++) { /* setup the red information */ { low_shade = (unsigned char) (i / red_colors_per_shade); high_shade = low_shade + 1; index = (unsigned short) (((i - low_shade * red_colors_per_shade) / red_colors_per_shade) * (DITHER_LEVEL * DITHER_LEVEL + 1)); low_shade *= red_mult; high_shade *= red_mult; red_dither[i] = (index << 16) + (high_shade << 8) + (low_shade); } /* setup the green information */ { low_shade = (unsigned char) (i / green_colors_per_shade); high_shade = low_shade + 1; index = (unsigned short) (((i - low_shade * green_colors_per_shade) / green_colors_per_shade) * (DITHER_LEVEL * DITHER_LEVEL + 1)); low_shade *= green_mult; high_shade *= green_mult; green_dither[i] = (index << 16) + (high_shade << 8) + (low_shade); } /* setup the blue information */ { low_shade = (unsigned char) (i / blue_colors_per_shade); high_shade = low_shade + 1; index = (unsigned short) (((i - low_shade * blue_colors_per_shade) / blue_colors_per_shade) * (DITHER_LEVEL * DITHER_LEVEL + 1)); blue_dither[i] = (index << 16) + (high_shade << 8) + (low_shade); } /* setup the gray information */ { low_shade = (unsigned char) (i / gray_colors_per_shade); high_shade = low_shade + 1; index = (unsigned short) (((i - low_shade * gray_colors_per_shade) / gray_colors_per_shade) * (DITHER_LEVEL * DITHER_LEVEL + 1)); gray_dither[i] = (index << 16) + (high_shade << 8) + (low_shade); } } } void dither_line_color(unsigned char *src, unsigned char *dest, int y, int width) { register long a, b; long *ymod, xmod; ymod = DM[y & DITHER_MASK]; while (width--) { xmod = width & DITHER_MASK; b = red_dither[*(src++)]; if (ymod[xmod] < b) b >>= 8; a = green_dither[*(src++)]; if (ymod[xmod] < a) a >>= 8; b += a; a = blue_dither[*(src++)]; if (ymod[xmod] < a) a >>= 8; b += a; *(dest++) = b & 0xff; } } void dither_line_gray(unsigned char *src, unsigned char *dest, int y, int width) { long *ymod, xmod; register long a,g; ymod = DM[y & DITHER_MASK]; while (width--) { xmod = width & DITHER_MASK; #if 1 g = (src[0]*3 + src[1]*6 + src[2]) / 10; a = gray_dither[g]; src += 3; #else a = gray_dither[*(src++)]; #endif if (ymod[xmod] < a) a >>= 8; *(dest++) = a & 0xff; } } fbi-2.10/man.c0000644000175000017500000000573712506525033011260 0ustar jmmjmm/* * motif-based man page renderer * (c) 2001 Gerd Hoffmann * */ #include #include #include #include #include #include #include #include #include #include #include #include "RegEdit.h" #include "man.h" extern Display *dpy; extern Widget app_shell; /*----------------------------------------------------------------------*/ #define MAN_UNDEF 0 #define MAN_NORMAL 1 #define MAN_BOLD 2 #define MAN_UNDERLINE 3 static XmStringTag man_tags[] = { NULL, NULL, "bold", "underline" }; static void man_destroy(Widget widget, XtPointer clientdata, XtPointer call_data) { XtDestroyWidget(clientdata); } void man(char *page) { Widget dlg,view,label; XmString xmpage,xmchunk; char line[1024],chunk[256]; int s,d,cur,last; FILE *fp; /* build dialog */ dlg = XmCreatePromptDialog(app_shell,"man",NULL,0); XmdRegisterEditres(XtParent(dlg)); XtUnmanageChild(XmSelectionBoxGetChild(dlg,XmDIALOG_SELECTION_LABEL)); XtUnmanageChild(XmSelectionBoxGetChild(dlg,XmDIALOG_HELP_BUTTON)); XtUnmanageChild(XmSelectionBoxGetChild(dlg,XmDIALOG_CANCEL_BUTTON)); XtUnmanageChild(XmSelectionBoxGetChild(dlg,XmDIALOG_TEXT)); XtAddCallback(dlg,XmNokCallback,man_destroy,dlg); view = XmCreateScrolledWindow(dlg,"view",NULL,0); XtManageChild(view); label = XtVaCreateManagedWidget("label", xmLabelWidgetClass,view, NULL); XtManageChild(dlg); /* fetch page and render into XmString */ sprintf(line,"man %s 2>/dev/null",page); fp = popen(line,"r"); xmpage = XmStringGenerate("", NULL, XmMULTIBYTE_TEXT, NULL); while (NULL != fgets(line,sizeof(line)-1,fp)) { last = MAN_UNDEF; for (s = 0, d = 0; line[s] != '\0';) { /* check current char */ cur = MAN_NORMAL; if (line[s+1] == '\010' && line[s] == line[s+2]) cur = MAN_BOLD; if (line[s] == '_' && line[s+1] == '\010') cur = MAN_UNDERLINE; /* add chunk if completed */ if (MAN_UNDEF != last && cur != last) { xmchunk = XmStringGenerate(chunk,NULL,XmMULTIBYTE_TEXT, man_tags[last]); xmpage = XmStringConcatAndFree(xmpage,xmchunk); d = 0; } /* add char to chunk */ switch (cur) { case MAN_BOLD: case MAN_UNDERLINE: s += 2; case MAN_NORMAL: chunk[d++] = line[s++]; break; } chunk[d] = '\0'; last = cur; } /* add last chunk for line */ xmchunk = XmStringGenerate(chunk, NULL, XmMULTIBYTE_TEXT, man_tags[last]); xmpage = XmStringConcatAndFree(xmpage,xmchunk); } XtVaSetValues(label,XmNlabelString,xmpage,NULL); XmStringFree(xmpage); fclose(fp); } void man_cb(Widget widget, XtPointer clientdata, XtPointer call_data) { char *page = clientdata; man(page); } void man_action(Widget widget, XEvent *event, String *params, Cardinal *num_params) { if (*num_params > 0) man(params[0]); } fbi-2.10/README0000644000175000017500000000206212506525033011205 0ustar jmmjmm what is it? =========== Ida is a small and fast image viewer, motif-based. For people who don't want the KDE/GNOME overhead. Some basic editing functions are available too. build ===== Check the INSTALL file for detailed build instructions. ida uses Motif 2.x features (utm, render tables). This means you need openmotif, lesstif does *not* cut it. It also uses the usual graphics libraries (libtiff, libpng, libjpeg, ...), you should have them installed to get support for these image formats. usage ===== There is a manual page, check it out. what "ida" stands for? ====================== It is just a name. The utility used to be named "iv" for "Image Viewer", but that gave lots of name clashes. Its very likely that people name such a tool "iv", it is also used as shortcut for InterViews (remember Sun's Open Windows?). So i decided to rename it. I looked for a short name starting with 'i' in a list for children first names. I like "ida", so I picked this one. It is a old, german name. Have fun, Gerd -- Gerd Hoffmann fbi-2.10/thumbnail.cgi.c0000644000175000017500000000674512506525033013231 0ustar jmmjmm#include #include #include #include #include #include #include #include #include /* -------------------------------------------------------------------------- */ static const char *shellhelp = "\n" "This is a cgi script. It doesn't do any useful (beside printing this text)\n" "when started from the shell prompt, it is supposed to be started by your\n" "web server\n"; static const char *description = "\n" "The script deliveres the EXIF thumbnail of JPEG images to the web browser.\n" "It will lookup the path passed via path info below your document root, i.e.\n" "a request like this ...\n" "\n" " http://your.server/cgi-bin/thumbnail.cgi/path/file.jpg\n" "\n" "... will make the script send the thumbnail of the file ...\n" "\n" " %s/path/file.jpg\n" "\n" "to the client\n" "\n" "Security note: The script refuses paths containing \"..\" to avoid breaking\n" "out of the document root. There are no other checks through, so it will\n" "deliver thumbnails for any JPEG image below below your document root which\n" "it is allowed to open by unix file permissions.\n" "\n" "(c) 2004 Gerd Hoffmann [SUSE Labs]\n" "\n"; /* -------------------------------------------------------------------------- */ static void panic(int code, char *message) { printf("Status: %d %s\n" "Content-Type: text/plain\n" "\n" "ERROR: %s\n", code, message, message); fflush(stdout); exit(1); } static void dump_thumbnail(char *filename) { char *cached; char mtime[64]; struct stat st; struct tm *tm; ExifData *ed = NULL; if (-1 == stat(filename,&st)) panic(404,"can't stat file"); tm = gmtime(&st.st_mtime); strftime(mtime,sizeof(mtime),"%a, %d %b %Y %H:%M:%S GMT",tm); cached = getenv("HTTP_IF_MODIFIED_SINCE"); if (NULL != cached && 0 == strcmp(cached,mtime)) { /* shortcut -- browser has a up-to-date copy */ printf("Status: 304 Image not modified\n" "\n"); fflush(stdout); return; } ed = exif_data_new_from_file(filename); if (!ed) panic(500,"file has no exif data\n"); if (!ed->data) panic(500,"no exif thumbnail present"); if (ed->data[0] != 0xff || ed->data[1] != 0xd8) panic(500,"exif thumbnail has no jpeg magic"); printf("Status: 200 Thumbnail follows\n" "Content-Type: image/jpeg\n" "Content-Length: %d\n" "Last-modified: %s\n" "\n", ed->size,mtime); fwrite(ed->data,ed->size,1,stdout); fflush(stdout); } /* -------------------------------------------------------------------------- */ int main(int argc, char *argv[]) { char filename[1024]; char *document_root; char *path_info; if (NULL == getenv("GATEWAY_INTERFACE")) { fprintf(stderr,"%s", shellhelp); fprintf(stderr,description,"$DOCUMENT_ROOT"); exit(1); } document_root = getenv("DOCUMENT_ROOT"); if (NULL == document_root) panic(500,"DOCUMENT_ROOT unset"); path_info = getenv("PATH_INFO"); if (NULL == path_info || 0 == strlen(path_info)) { printf("Content-type: text/plain\n" "\n"); printf(description,document_root); fflush(stdout); return 0; } if (NULL != strstr(path_info,"..")) panic(403,"\"..\" not allowed in path"); snprintf(filename,sizeof(filename),"%s/%s",document_root,path_info); dump_thumbnail(filename); return 0; } fbi-2.10/x11.c0000644000175000017500000003002112506525033011076 0ustar jmmjmm/* * some X11 ximage / pixmaps rotines * * (c) 1996 Gerd Hoffmann * * basic usage: * 1) call x11_color_init() * this does all the visual checking/colormap handling stuff and returns * TRUECOLOR or PSEUDOCOLOR * 2) create/load the image * 3) call x11_create_pixmaps() * For TRUECOLOR: It expects the data in one long (4 byte) per pixel. * To create the long, run the rgb-values throuth the * x11_lut_[red|green|blue] tables and or the results * For PSEUDOCOLOR: The data is expected to be one byte per pixel, * containing the results from dither_line (see dither.c) * Not required to call init_dither, this is done by * x11_color_init * returns a pixmap. * */ #include #include #include #include #include #include #include #include #include #include #include #include "x11.h" #include "dither.h" extern Display *dpy; #define PERROR(str) fprintf(stderr,"%s:%d: %s: %s\n",__FILE__,__LINE__,str,strerror(errno)) /* ------------------------------------------------------------------------ */ int display_type = 0; int display_depth = 0; XVisualInfo *info; /* PseudoColor: ditherresult => colormap-entry */ int x11_colors; int x11_grays; unsigned long *x11_map; unsigned long x11_map_color[256]; unsigned long x11_map_gray[64]; unsigned long x11_red; unsigned long x11_green; unsigned long x11_blue; int have_shmem = 0; /* * - xv uses 4:8:4 for truecolor images. * - The GIMP 0.99.9 uses 6:6:4, but the 6 intervals for red+green are * choosen somehow wired :-( * - ImageMagick tries to optimize the palette for each image individual */ static int try_red[] = {4, 6, 6, 5, 4}; static int try_green[] = {8, 6, 6, 5, 4}; static int try_blue[] = {4, 6, 4, 5, 4}; /* TrueColor: r,g,b => X11-color */ unsigned long x11_lut_red[256]; unsigned long x11_lut_green[256]; unsigned long x11_lut_blue[256]; unsigned long x11_lut_gray[256]; static int x11_alloc_grays(Display * dpy, Colormap cmap, unsigned long *colors, int gray) { XColor akt_color; int i; for (i = 0; i < gray; i++) { akt_color.red = i * 65535 / (gray - 1); akt_color.green = i * 65535 / (gray - 1); akt_color.blue = i * 65535 / (gray - 1); if (!XAllocColor(dpy, cmap, &akt_color)) { /* failed, free them */ XFreeColors(dpy, cmap, colors, i, 0); return 1; } colors[i] = akt_color.pixel; #if 0 fprintf(stderr, "%2lx: %04x %04x %04x\n", akt_color.pixel,akt_color.red,akt_color.green,akt_color.red); #endif } return 0; } static int x11_alloc_colorcube(Display * dpy, Colormap cmap, unsigned long *colors, int red, int green, int blue) { XColor akt_color; int i; for (i = 0; i < red * green * blue; i++) { akt_color.red = ((i / (green * blue)) % red) * 65535 / (red - 1); akt_color.green = ((i / blue) % green) * 65535 / (green - 1); akt_color.blue = (i % blue) * 65535 / (blue - 1); #if 0 fprintf(stderr, "%04x %04x %04x\n", akt_color.red, akt_color.green, akt_color.red); #endif if (!XAllocColor(dpy, cmap, &akt_color)) { /* failed, free them */ XFreeColors(dpy, cmap, colors, i, 0); return 1; } colors[i] = akt_color.pixel; } return 0; } static unsigned long x11_alloc_color(Display * dpy, Colormap cmap, int red, int green, int blue) { XColor akt_color; akt_color.red = red; akt_color.green = green; akt_color.blue = blue; XAllocColor(dpy, cmap, &akt_color); return akt_color.pixel; } static void x11_create_lut(unsigned long red_mask, unsigned long green_mask, unsigned long blue_mask) { int rgb_red_bits = 0; int rgb_red_shift = 0; int rgb_green_bits = 0; int rgb_green_shift = 0; int rgb_blue_bits = 0; int rgb_blue_shift = 0; int i; unsigned long mask; for (i = 0; i < 24; i++) { mask = (1 << i); if (red_mask & mask) rgb_red_bits++; else if (!rgb_red_bits) rgb_red_shift++; if (green_mask & mask) rgb_green_bits++; else if (!rgb_green_bits) rgb_green_shift++; if (blue_mask & mask) rgb_blue_bits++; else if (!rgb_blue_bits) rgb_blue_shift++; } #if 0 printf("color: bits shift\n"); printf("red : %04i %05i\n", rgb_red_bits, rgb_red_shift); printf("green: %04i %05i\n", rgb_green_bits, rgb_green_shift); printf("blue : %04i %05i\n", rgb_blue_bits, rgb_blue_shift); #endif for (i = 0; i < 256; i++) { x11_lut_red[i] = (i >> (8 - rgb_red_bits)) << rgb_red_shift; x11_lut_green[i] = (i >> (8 - rgb_green_bits)) << rgb_green_shift; x11_lut_blue[i] = (i >> (8 - rgb_blue_bits)) << rgb_blue_shift; x11_lut_gray[i] = x11_lut_red[i] | x11_lut_green[i] | x11_lut_blue[i]; } } int x11_color_init(Widget shell, int *gray) { Screen *scr; Colormap cmap; XVisualInfo template; unsigned int found, i; scr = XtScreen(shell); cmap = DefaultColormapOfScreen(scr); if (0 == x11_grays) x11_grays = 8; /* Ask for visual type */ template.screen = XDefaultScreen(dpy); template.visualid = XVisualIDFromVisual(DefaultVisualOfScreen(scr)); info = XGetVisualInfo(dpy, VisualIDMask | VisualScreenMask, &template, &found); if (XShmQueryExtension(dpy)) { have_shmem = 1; } /* display_depth = (info->depth+7)/8; */ if (info->class == TrueColor) { /* TrueColor */ *gray = 0; /* XXX testing... */ display_depth = 4; display_type = TRUECOLOR; x11_create_lut(info->red_mask, info->green_mask, info->blue_mask); x11_black = x11_alloc_color(dpy, cmap, 0, 0, 0); x11_gray = x11_alloc_color(dpy, cmap, 0xc400, 0xc400, 0xc400); x11_lightgray = x11_alloc_color(dpy, cmap, 0xe000, 0xe000, 0xe000); x11_white = x11_alloc_color(dpy, cmap, 0xffff, 0xffff, 0xffff); } else if (info->class == PseudoColor && info->depth == 8) { /* 8bit PseudoColor */ display_depth = 1; display_type = PSEUDOCOLOR; if (0 != x11_alloc_grays(dpy, cmap, x11_map_gray, x11_grays)) { fprintf(stderr, "sorry, can't allocate %d grays\n", x11_grays); exit(1); } if (!*gray) { for (i = 0; i < sizeof(try_red) / sizeof(int); i++) { if (0 == x11_alloc_colorcube (dpy, cmap, x11_map_color, try_red[i], try_green[i], try_blue[i])) { x11_colors = try_red[i] * try_green[i] * try_blue[i]; init_dither(try_red[i], try_green[i], try_blue[i], x11_grays); break; } } if (i == sizeof(try_red) / sizeof(int)) { *gray = 1; fprintf(stderr, "failed to allocate enouth colors, " "using grayscaled\n"); } } if (*gray) init_dither(2, 2, 2, x11_grays); } else if (info->class == StaticGray || info->class == GrayScale) { /* Grayscale */ display_depth = 1; display_type = PSEUDOCOLOR; x11_grays = 64; *gray = 1; init_dither(2, 2, 2, x11_grays); if (0 != x11_alloc_grays(dpy, cmap, x11_map_gray, x11_grays)) { fprintf(stderr, "sorry, can't allocate %d grays\n", x11_grays); exit(1); } } else { fprintf(stderr, "sorry, can't handle visual\n"); exit(1); } /* some common colors */ x11_red = x11_alloc_color(dpy, cmap, 65535, 0, 0); x11_green = x11_alloc_color(dpy, cmap, 0, 65535, 0); x11_blue = x11_alloc_color(dpy, cmap, 0, 0, 65535); if (*gray) { x11_map = x11_map_gray; dither_line = dither_line_gray; } else { x11_map = x11_map_color; dither_line = dither_line_color; } return display_type; } /* ------------------------------------------------------------------------ */ static int mitshm_bang = 0; static int x11_error_dev_null(Display * dpy, XErrorEvent * event) { mitshm_bang = 1; return 0; } XImage* x11_create_ximage(Widget shell, int width, int height, void **shm) { XImage *ximage = NULL; unsigned char *ximage_data; XShmSegmentInfo *shminfo = NULL; XtPointer old_handler; Screen *scr = XtScreen(shell); if (have_shmem) { old_handler = XSetErrorHandler(x11_error_dev_null); (*shm) = shminfo = malloc(sizeof(XShmSegmentInfo)); memset(shminfo, 0, sizeof(XShmSegmentInfo)); ximage = XShmCreateImage(dpy, DefaultVisualOfScreen(scr), DefaultDepthOfScreen(scr), ZPixmap, NULL, shminfo, width, height); if (ximage) { shminfo->shmid = shmget(IPC_PRIVATE, ximage->bytes_per_line * ximage->height, IPC_CREAT | 0777); if (-1 == shminfo->shmid) { fprintf(stderr,"shmget(%dMB): %s\n", ximage->bytes_per_line * ximage->height / 1024 / 1024, strerror(errno)); goto oom; } shminfo->shmaddr = (char *) shmat(shminfo->shmid, 0, 0); if ((void *) -1 == shminfo->shmaddr) { perror("shmat"); goto oom; } ximage->data = shminfo->shmaddr; shminfo->readOnly = False; XShmAttach(dpy, shminfo); XSync(dpy, False); shmctl(shminfo->shmid, IPC_RMID, 0); if (mitshm_bang) { have_shmem = 0; shmdt(shminfo->shmaddr); free(shminfo); shminfo = *shm = NULL; XDestroyImage(ximage); ximage = NULL; } } else { have_shmem = 0; free(shminfo); shminfo = *shm = NULL; } XSetErrorHandler(old_handler); } if (ximage == NULL) { (*shm) = NULL; if (NULL == (ximage_data = malloc(width * height * display_depth))) { fprintf(stderr,"Oops: out of memory\n"); goto oom; } ximage = XCreateImage(dpy, DefaultVisualOfScreen(scr), DefaultDepthOfScreen(scr), ZPixmap, 0, ximage_data, width, height, 8, 0); } memset(ximage->data, 0, ximage->bytes_per_line * ximage->height); return ximage; oom: if (shminfo) { if (shminfo->shmid && shminfo->shmid != -1) shmctl(shminfo->shmid, IPC_RMID, 0); free(shminfo); } if (ximage) XDestroyImage(ximage); return NULL; } void x11_destroy_ximage(Widget shell, XImage * ximage, void *shm) { XShmSegmentInfo *shminfo = shm; if (shminfo) { XShmDetach(dpy, shminfo); XDestroyImage(ximage); shmdt(shminfo->shmaddr); free(shminfo); } else XDestroyImage(ximage); } Pixmap x11_create_pixmap(Widget shell, unsigned char *byte_data, int width, int height, int gray) { Pixmap pixmap; XImage *ximage; XGCValues values; GC gc; unsigned long *long_data = (unsigned long *) byte_data; int x, y; void *shm; unsigned long *map = gray ? x11_map_gray : x11_map; Screen *scr = XtScreen(shell); pixmap = XCreatePixmap(dpy, RootWindowOfScreen(scr), width, height, DefaultDepthOfScreen(scr)); gc = XCreateGC(dpy, pixmap, 0, &values); if (NULL == (ximage = x11_create_ximage(shell, width, height, &shm))) { XFreePixmap(dpy, pixmap); XFreeGC(dpy, gc); return 0; } for (y = 0; y < height; y++) if (display_type == TRUECOLOR) for (x = 0; x < width; x++) XPutPixel(ximage, x, y, *(long_data++)); else for (x = 0; x < width; x++) XPutPixel(ximage, x, y, map[(int) (*(byte_data++))]); XPUTIMAGE(dpy, pixmap, gc, ximage, 0, 0, 0, 0, width, height); x11_destroy_ximage(shell, ximage, shm); XFreeGC(dpy, gc); return pixmap; } void x11_data_to_ximage(unsigned char *data, unsigned char *ximage, int x, int y, int sy, int gray) { unsigned long *d; int i, n; if (display_type == PSEUDOCOLOR) { if (gray) { for (i = 0; i < y; i++) dither_line_gray(data + x * i, ximage + x * i, i + sy, x); } else { for (i = 0; i < y; i++) dither_line(data + 3 * x * i, ximage + x * i, i + sy, x); } } else { d = (unsigned long *) ximage; if (gray) { n = x * y; for (i = 0; i < n; i++) *(d++) = x11_lut_gray[data[i]]; } else { n = 3 * x * y; for (i = 0; i < n; i += 3) *(d++) = x11_lut_red[data[i]] | x11_lut_green[data[i + 1]] | x11_lut_blue[data[i + 2]]; } } } fbi-2.10/Changes0000644000175000017500000000731612506525033011627 0ustar jmmjmm 0.21 ==== * add support to edit jpeg comments. * various minor fixes/tweaks. 0.20 ==== * file browser code is largely rewritten. * added support to maintain file lists. * lots of minor tweaks. 0.19 ==== * url support for most image formats. 0.16 => 0.17 ============ * fixed some signed/unsigned bugs. * fixed tiff loader bug. * utf-8 locale crash workaround. 0.15 => 0.16 ============ * ditched autotools crap into the waste basket. * fixed plenty of gcc 3.3 warnings. * file browser improvements. * tweaked font sets. * multiplage support (Andrey Kiselev). 0.14 => 0.15 ============ * more tiff loader fixes (based on patches by Andrey Kiselev ). * png loader fixes. 0.13 => 0.14 ============ * tiff loader fixes (for b/w images). * Made pixmap selection transfer less strict. 0.12 => 0.13 ============ * fixed selections / clipboard / cut+paste handling. * fixed some warnings. * dropped extra "make depend" pass from build proccess. 0.11 => 0.12 ============ * added tooltips (needs OpenMotif 2.2 to work). * made the scale image dialog take care about image resolution. * some fixes in sane code. * man page updates. * unbundled libpcd. 0.10 => 0.11 ============ * renamed "iv" to "ida". * hex viewer fixes. * [ fixme: weipunkt ] * sane support. * keep track of the image resolution * The image size for printing / PostScript export defaults to the original size (calculated from image resolution if available). 0.9 => 0.10 =========== * do scaling with floats to avoid rounding errors with large scale factors. * fixed segfault with huge zoom factors / huge images. * need a new name for the utility, "iv" has way to much name clashes. ideas are welcome ... 0.8 => 0.9 ========== * fixed memory leak in file browser. 0.7 => 0.8 ========== * added loader for (uncompressed) windows bitmap files. * some minor changes for image save code - can write tmp files cleanly now. DnD for uses jpeg for tmp files, so you can drop them into netscape. * added loader for xbm files. * Some minor DnD fixes. * better "busy cursor" handling. * added wildcards filter to the file browser * file browser DnD fixes. * made PhotoCD resolution switchable at runtime. 0.6 => 0.7 ========== * added some handlers for selection data transfer, for clipboard + drag'n'drop support. 0.5 => 0.6 ========== * added simple file browser. * fixed bugs in png image loader. * fixed a bug in the gif loader. * figured out that libungif 4.1 is broken (if iv segfaults when loading gif images, try downgrading to libungif 3.0 + rebuild) * added autocrop. * added print dialog. * added blur,sharpe and emboss filters. 0.4 => 0.5 ========== * add options for image saving (jpeg, PostScript). * added PNG write support. 0.3 => 0.4 ========== * Added resize. * Added free rotation. * Added edge detect filter. * Some fine tuning here and there. * Added i18n + german translation. 0.2 => 0.3 ========== * added PhotoCD support. * fixed some minor nitpicks. * added toolbar. * added support for writing tiff images. * most image operations look at the selected area now. * added support for writing Postscript. Needs more work, not configurable yet (does: A4, portrait, image centered and scaled to max size with same aspect ratio). 0.1 => 0.2 ========== * implemented saving (ppm, jpeg). * redirect stderr to a message box. * color editor works. * fixed a bug in the gif loader. * fixed bugs in the tiff loader. * added -debug + -help command line switches. * added x window dump loader. * added support for reading images from stdin (you can now do screenshots using "xwd | iv -" for example). * added one-level undo. * added crop fbi-2.10/mk/0000755000175000017500000000000012506525033010734 5ustar jmmjmmfbi-2.10/mk/Compile.mk0000644000175000017500000000423112506525033012655 0ustar jmmjmm# # some rules to compile stuff ... # # (c) 2002-2006 Gerd Hoffmann # # main features: # * autodependencies via "cpp -MD" # * fancy, non-verbose output # # This file is public domain. No warranty. If it breaks you keep # both pieces. # ######################################################################## # verbose yes/no verbose ?= no # dependency files tmpdep = mk/$(subst /,_,$*).tmp depfile = mk/$(subst /,_,$*).dep depfiles = mk/*.dep compile_c = $(CC) $(CFLAGS) -Wp,-MD,$(tmpdep) -c -o $@ $< compile_c_pic = $(CC) $(CFLAGS) -fPIC -Wp,-MD,$(tmpdep) -c -o $@ $< compile_cc = $(CXX) $(CXXFLAGS) -Wp,-MD,$(tmpdep) -c -o $@ $< fixup_deps = sed -e "s|.*\.o:|$@:|" < $(tmpdep) > $(depfile) && rm -f $(tmpdep) cc_makedirs = mkdir -p $(dir $@) $(dir $(depfile)) link_app = $(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS) link_so = $(CC) $(LDFLAGS) -shared -Wl,-soname,$(@F) -o $@ $^ $(LDLIBS) ar_lib = rm -f $@ && ar -r $@ $^ && ranlib $@ moc_h = $(MOC) $< -o $@ msgfmt_po = msgfmt -o $@ $< # non-verbose output ifeq ($(verbose),no) echo_compile_c = echo " CC " $@ echo_compile_c_pic = echo " CC " $@ echo_compile_cc = echo " CXX " $@ echo_link_app = echo " LD " $@ echo_link_so = echo " LD " $@ echo_ar_lib = echo " AR " $@ echo_moc_h = echo " MOC " $@ echo_msgfmt_po = echo " MSGFMT " $@ else echo_compile_c = echo $(compile_c) echo_compile_c_pic = echo $(compile_c_pic) echo_compile_cc = echo $(compile_cc) echo_link_app = echo $(link_app) echo_link_so = echo $(link_so) echo_ar_lib = echo $(ar_lib) echo_moc_h = echo $(moc_h) echo_msgfmt_po = echo $(msgfmt_po) endif %.o: %.c @$(cc_makedirs) @$(echo_compile_c) @$(compile_c) @$(fixup_deps) %.opic: %.c @$(cc_makedirs) @$(echo_compile_c_pic) @$(compile_c_pic) @$(fixup_deps) %.o: %.cc @$(cc_makedirs) @$(echo_compile_cc) @$(compile_cc) @$(fixup_deps) %.o: %.cpp @$(cc_makedirs) @$(echo_compile_cc) @$(compile_cc) @$(fixup_deps) %: %.o @$(echo_link_app) @$(link_app) %.so: %.o @$(echo_link_so) @$(link_so) %.a: %.o @$(echo_ar_lib) @$(ar_lib) %.moc : %.h @$(echo_moc_h) @$(moc_h) %.mo : %.po @$(echo_msgfmt_po) @$(msgfmt_po) fbi-2.10/mk/Autoconf.mk0000644000175000017500000001102512506525033013042 0ustar jmmjmm# # simple autoconf system for GNU make # # (c) 2002-2006 Gerd Hoffmann # # credits for creating this one go to the autotools people because # they managed it to annoy lots of developers and users (including # me) with version incompatibilities. # # This file is public domain. No warranty. If it breaks you keep # both pieces. # ######################################################################## # verbose yes/no verbose ?= no # some stuff used by the tests ifneq ($(verbose),no) # verbose (for debug) ac_init = echo "checking $(1) ... " >&2; rc=no ac_b_cmd = echo "run: $(1)" >&2; $(1) >/dev/null && rc=yes ac_s_cmd = echo "run: $(1)" >&2; rc=`$(1)` ac_fini = echo "... result is $${rc}" >&2; echo >&2; echo "$${rc}" else # normal ac_init = echo -n "checking $(1) ... " >&2; rc=no ac_b_cmd = $(1) >/dev/null 2>&1 && rc=yes ac_s_cmd = rc=`$(1) 2>/dev/null` ac_fini = echo "$${rc}" >&2; echo "$${rc}" endif # some helpers to build cflags and related variables ac_def_cflags_1 = $(if $(filter yes,$($(1))),-D$(1)) ac_lib_cflags = $(foreach lib,$(1),$(call ac_def_cflags_1,HAVE_LIB$(lib))) ac_inc_cflags = $(foreach inc,$(1),$(call ac_def_cflags_1,HAVE_$(inc))) ac_lib_mkvar_1 = $(if $(filter yes,$(HAVE_LIB$(1))),$($(1)_$(2))) ac_lib_mkvar = $(foreach lib,$(1),$(call ac_lib_mkvar_1,$(lib),$(2))) ######################################################################## # the tests ... # get uname ac_uname = $(shell \ $(call ac_init,for system);\ $(call ac_s_cmd,uname -s | tr 'A-Z' 'a-z');\ $(call ac_fini)) ac_uname_arch = $(shell \ $(call ac_init,for arch);\ $(call ac_s_cmd,uname -m | tr 'A-Z' 'a-z');\ $(call ac_fini)) # check for some header file # args: header file ac_header = $(shell \ $(call ac_init,for $(1));\ $(call ac_b_cmd,echo '\#include <$(1)>' |\ $(CC) $(CFLAGS) -E -);\ $(call ac_fini)) # check for some function # args: function [, additional libs ] ac_func = $(shell \ $(call ac_init,for $(1));\ echo 'void $(1)(void); int main(void) {$(1)();return 0;}' \ > __actest.c;\ $(call ac_b_cmd,$(CC) $(CFLAGS) $(LDFLAGS) -o \ __actest __actest.c $(2));\ rm -f __actest __actest.c;\ $(call ac_fini)) # check for some library # args: function, library [, additional libs ] ac_lib = $(shell \ $(call ac_init,for $(1) in $(2));\ echo 'void $(1)(void); int main(void) {$(1)();return 0;}' \ > __actest.c;\ $(call ac_b_cmd,$(CC) $(CFLAGS) $(LDFLAGS) -o \ __actest __actest.c -l$(2) $(3));\ rm -f __actest __actest.c;\ $(call ac_fini)) # check if some compiler flag works # args: compiler flag ac_cflag = $(shell \ $(call ac_init,for $(CC) cflags);\ echo 'int main() {return 0;}' > __actest.c;\ $(call ac_b_cmd,$(CC) $(CFLAGS) $(1) $(LDFLAGS) -o \ __actest __actest.c);\ rm -f __actest __actest.c;\ if test "$${rc}" = "yes"; then rc="$(1)"; else rc="$(2)"; fi;\ $(call ac_fini)) # check for some binary # args: binary name ac_binary = $(shell \ $(call ac_init,for $(1));\ $(call ac_s_cmd,which $(1));\ bin="$$rc";rc="no";\ $(call ac_b_cmd,test -x "$$$$bin");\ $(call ac_fini)) # check if lib64 is used #ac_lib64 = $(shell \ # $(call ac_init,for libdir name);\ # $(call ac_s_cmd,$(CC) -print-search-dirs | grep -q lib64 &&\ # echo "lib64" || echo "lib");\ # $(call ac_fini)) ac_lib64 = $(shell \ $(call ac_init,for libdir name);\ $(call ac_s_cmd,/sbin/ldconfig -p | grep -q lib64 &&\ echo "lib64" || echo "lib");\ $(call ac_fini)) # check for x11 ressource dir prefix ac_resdir = $(shell \ $(call ac_init,for X11 app-defaults prefix);\ $(call ac_s_cmd, for dir in \ /etc/X11/app-defaults \ /usr/X11R6/lib/X11/app-defaults \ /usr/share/X11/app-defaults \ /usr/lib/X11/app-defaults \ ; do test -d "$$dir" || continue;\ dirname "$$dir"; break; done);\ $(call ac_fini)) # check if package is installed, via pkg-config # args: pkg name ac_pkg_config = $(shell \ $(call ac_init,for $(1) (using pkg-config));\ $(call ac_b_cmd, pkg-config $(1));\ $(call ac_fini)) # grep some file # args: regex, file ac_grep = $(shell \ $(call ac_init,for $(1) in $(2));\ $(call ac_b_cmd, grep -q $(1) $(2));\ $(call ac_fini)) ######################################################################## # build Make.config define newline endef make-config-q = $(subst $(newline),\n,$(make-config)) ifeq ($(filter config,$(MAKECMDGOALS)),config) .PHONY: Make.config LIB := $(call ac_lib64) else LIB ?= $(call ac_lib64) LIB := $(LIB) endif .PHONY: config config: Make.config @true Make.config: $(srcdir)/GNUmakefile @printf "$(make-config-q)" > $@ @echo @echo "Make.config written, edit if needed" @echo fbi-2.10/mk/Variables.mk0000644000175000017500000000243412506525033013200 0ustar jmmjmm# common variables ... ######################################################################## # directories DESTDIR = srcdir ?= . prefix ?= /usr/local bindir = $(DESTDIR)$(prefix)/bin sbindir = $(DESTDIR)$(prefix)/sbin libdir = $(DESTDIR)$(prefix)/$(LIB) shrdir = $(DESTDIR)$(prefix)/share mandir = $(shrdir)/man locdir = $(shrdir)/locale appdir = $(shrdir)/applications # package + version empty := space := $(empty) $(empty) ifneq ($(wildcard $(srcdir)/VERSION),) VERSION := $(shell cat $(srcdir)/VERSION) else VERSION := 42 endif RELTAG := v$(subst .,_,$(VERSION)) # programs CC ?= gcc CXX ?= g++ MOC ?= $(if $(QTDIR),$(QTDIR)/bin/moc,moc) STRIP ?= -s INSTALL ?= install INSTALL_BINARY := $(INSTALL) $(STRIP) INSTALL_SCRIPT := $(INSTALL) INSTALL_DATA := $(INSTALL) -m 644 INSTALL_DIR := $(INSTALL) -d # cflags CFLAGS ?= -g -O2 CXXFLAGS ?= $(CFLAGS) CFLAGS += -Wall -Wmissing-prototypes -Wstrict-prototypes \ -Wpointer-arith -Wunused CXXFLAGS += -Wall -Wpointer-arith -Wunused # add /usr/local to the search path if something is in there ... ifneq ($(wildcard /usr/local/include/*.h),) CFLAGS += -I/usr/local/include LDFLAGS += -L/usr/local/$(LIB) endif # fixup include path for $(srcdir) != "." ifneq ($(srcdir),.) CFLAGS += -I. -I$(srcdir) endif fbi-2.10/mk/.cvsignore0000644000175000017500000000000612506525033012730 0ustar jmmjmm*.dep fbi-2.10/mk/.gitignore0000644000175000017500000000000612506525033012720 0ustar jmmjmm*.dep fbi-2.10/mk/Maintainer.mk0000644000175000017500000000163112506525033013355 0ustar jmmjmm# just some maintainer stuff for me ... ######################################################################## make-sync-dir = $(HOME)/projects/gnu-makefiles .PHONY: sync sync:: distclean test -d $(make-sync-dir) rm -f $(srcdir)/INSTALL $(srcdir)/mk/*.mk cp -v $(make-sync-dir)/INSTALL $(srcdir)/. cp -v $(make-sync-dir)/*.mk $(srcdir)/mk chmod 444 $(srcdir)/INSTALL $(srcdir)/mk/*.mk repository := $(shell basename $(PWD)) release-dir ?= $(HOME)/projects/Releases release-pub ?= bigendian.kraxel.org:/public/vhosts/www.kraxel.org/releases/$(repository) tarball = $(release-dir)/$(repository)-$(VERSION).tar $(tarball).gz: git tag -m "release $(VERSION)" "$(VERSION)" git push --tags git archive --format=tar --prefix=$(repository)-$(VERSION)/ \ -o $(tarball) $(VERSION) gzip $(tarball) .PHONY: release release: $(tarball).gz gpg --detach-sign --armor $(tarball).gz scp $(tarball).gz* $(release-pub) fbi-2.10/desktop.h0000644000175000017500000000055512506525033012154 0ustar jmmjmm/* these are "for free", the desktop file stuff needs this anyway ... */ int utf8_to_locale(char *src, char *dst, size_t max); int locale_to_utf8(char *src, char *dst, size_t max); /* handle desktop files */ int desktop_read_entry(char *filename, char *entry, char *dest, size_t max); int desktop_write_entry(char *filename, char *type, char *entry, char *value); fbi-2.10/xdnd.h0000644000175000017500000000032612506525033011434 0ustar jmmjmmextern int xdnd_debug; void XdndDropSink(Widget widget); void XdndAction(Widget widget, XEvent *event, String *params, Cardinal *num_params); void XdndDropFinished(Widget widget, XmSelectionCallbackStruct *scs); fbi-2.10/lut.c0000644000175000017500000000431312506525033011276 0ustar jmmjmm#include #include #include #include "readers.h" #include "viewer.h" #include "lut.h" /* ----------------------------------------------------------------------- */ struct op_map_parm_ch op_map_nothing = { gamma: 1, bottom: 0, top: 255, left: 0, right: 255 }; struct op_map_lut { unsigned char red[256]; unsigned char green[256]; unsigned char blue[256]; }; /* ----------------------------------------------------------------------- */ /* functions */ static void build_lut(struct op_map_parm_ch *arg, unsigned char *lut) { int i,val; int inrange,outrange; float p; inrange = arg->right - arg->left +1; outrange = arg->top - arg->bottom +1; p = 1/arg->gamma; for (i = 0; i < arg->left; i++) lut[i] = 0; for (; i <= arg->right; i++) { val = pow((float)(i-arg->left)/inrange,p) * outrange + 0.5; val += arg->bottom; if (val < 0) val = 0; if (val > 255) val = 255; lut[i] = val; } for (; i < 256; i++) lut[i] = 255; } static void* op_map_init(struct ida_image *src, struct ida_rect *rect, struct ida_image_info *i, void *parm) { struct op_map_parm *args = parm; struct op_map_lut *lut; lut = malloc(sizeof(*lut)); build_lut(&args->red,lut->red); build_lut(&args->green,lut->green); build_lut(&args->blue,lut->blue); *i = src->i; return lut; } static void op_map_work(struct ida_image *src, struct ida_rect *rect, unsigned char *dst, int line, void *data) { struct op_map_lut *lut = data; unsigned char *scanline; int i; scanline = src->data + line * src->i.width * 3; memcpy(dst,scanline,src->i.width * 3); if (line < rect->y1 || line >= rect->y2) return; dst += 3*rect->x1; scanline += 3*rect->x1; for (i = rect->x1; i < rect->x2; i++) { dst[0] = lut->red[scanline[0]]; dst[1] = lut->green[scanline[1]]; dst[2] = lut->blue[scanline[2]]; scanline += 3; dst += 3; } } /* ----------------------------------------------------------------------- */ struct ida_op desc_map = { name: "map", init: op_map_init, work: op_map_work, done: op_free_done, }; fbi-2.10/wr/0000755000175000017500000000000012506525033010755 5ustar jmmjmmfbi-2.10/wr/write-png.c0000644000175000017500000000425112506525033013037 0ustar jmmjmm#include #include #include #include #include #include #include #include "readers.h" #include "writers.h" #include "viewer.h" /* ---------------------------------------------------------------------- */ /* save */ static int png_write(FILE *fp, struct ida_image *img) { png_structp png_ptr = NULL; png_infop info_ptr = NULL; png_bytep row; unsigned int y; /* Create and initialize the png_struct with the desired error handler * functions. If you want to use the default stderr and longjump method, * you can supply NULL for the last three parameters. We also check that * the library version is compatible with the one used at compile time, * in case we are using dynamically linked libraries. REQUIRED. */ png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,NULL,NULL,NULL); if (png_ptr == NULL) goto oops; /* Allocate/initialize the image information data. REQUIRED */ info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL) goto oops; if (setjmp(png_jmpbuf(png_ptr))) goto oops; png_init_io(png_ptr, fp); png_set_IHDR(png_ptr, info_ptr, img->i.width, img->i.height, 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); if (img->i.dpi) { png_set_pHYs(png_ptr, info_ptr, res_inch_to_m(img->i.dpi), res_inch_to_m(img->i.dpi), PNG_RESOLUTION_METER); } png_write_info(png_ptr, info_ptr); png_set_packing(png_ptr); for (y = 0; y < img->i.height; y++) { row = img->data + y * 3 * img->i.width; png_write_rows(png_ptr, &row, 1); } png_write_end(png_ptr, info_ptr); png_destroy_write_struct(&png_ptr, &info_ptr); return 0; oops: fprintf(stderr,"can't save image: libpng error\n"); if (png_ptr) png_destroy_write_struct(&png_ptr, (png_infopp)NULL); return -1; } static struct ida_writer png_writer = { label: "PNG", ext: { "png", NULL}, write: png_write, }; static void __init init_wr(void) { write_register(&png_writer); } fbi-2.10/wr/Makefile0000644000175000017500000000003112506525033012407 0ustar jmmjmmdefault: cd ..; $(MAKE) fbi-2.10/wr/write-ps.c0000644000175000017500000002735512506525033012707 0ustar jmmjmm#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "RegEdit.h" #include "ida.h" #include "readers.h" #include "writers.h" #include "viewer.h" struct PAPER { char *name; int width,height; }; static struct PAPER formats[] = { { name: "A4", width: 595, height: 842, },{ name: "Letter", width: 612, height: 792, },{ /* EOF */ } }; static const char *header = "%%!PS-Adobe-2.0 EPSF-2.0\n" "%%%%Creator: ida " VERSION " (https://www.kraxel.org/blog/linux/fbida/)\n" "%%%%Pages: 1\n" "%%%%BoundingBox: %d %d %d %d\n" "%%%%DocumentFonts: \n" "%%%%EndComments\n" "%%%%EndProlog\n" "\n" "%%%%Page: 1 1" "\n" "/origstate save def\n" "20 dict begin\n"; static const char *footer = "\n" "showpage\n" "end\n" "origstate restore\n" "%%%%Trailer\n"; /* taken from xwd2ps, ftp://ftp.x.org/R5contrib/xwd2ps.tar.Z */ static const char *ColorImage = "% define 'colorimage' if it isn't defined\n" "% ('colortogray' and 'mergeprocs' come from xwd2ps\n" "% via xgrab)\n" "/colorimage where % do we know about 'colorimage'?\n" " { pop } % yes: pop off the 'dict' returned\n" " { % no: define one\n" " /colortogray { % define an RGB->I function\n" " /rgbdata exch store % call input 'rgbdata'\n" " rgbdata length 3 idiv\n" " /npixls exch store\n" " /rgbindx 0 store\n" " 0 1 npixls 1 sub {\n" " grays exch\n" " rgbdata rgbindx get 20 mul % Red\n" " rgbdata rgbindx 1 add get 32 mul % Green\n" " rgbdata rgbindx 2 add get 12 mul % Blue\n" " add add 64 idiv % I = .5G + .31R + .18B\n" " put\n" " /rgbindx rgbindx 3 add store\n" " } for\n" " grays 0 npixls getinterval\n" " } bind def\n" "\n" " % Utility procedure for colorimage operator.\n" " % This procedure takes two procedures off the\n" " % stack and merges them into a single procedure.\n" "\n" " /mergeprocs { % def\n" " dup length\n" " 3 -1 roll\n" " dup\n" " length\n" " dup\n" " 5 1 roll\n" " 3 -1 roll\n" " add\n" " array cvx\n" " dup\n" " 3 -1 roll\n" " 0 exch\n" " putinterval\n" " dup\n" " 4 2 roll\n" " putinterval\n" " } bind def\n" "\n" " /colorimage { % def\n" " pop pop % remove 'false 3' operands\n" " {colortogray} mergeprocs\n" " image\n" " } bind def\n" " } ifelse % end of 'false' case\n" "\n"; /* ---------------------------------------------------------------------- */ /* save */ #define PORTRAIT 0 #define LANDSCAPE 1 #define DRAW_SIZE 200 #define DRAW_SCALE 6 #define DSCALED(x) (((x)+DRAW_SCALE/2)/DRAW_SCALE) static struct ps_options { Widget shell,draw,scale,geo; int xscale,yscale; GC gc; int lastx,lasty; int format; int ori; int scaling; int iwidth,iheight,ires; int pwidth,pheight; int mwidth,mheight; int width,height,xcenter,ycenter; } ps; static void ps_draw(Widget widget, XtPointer client_data, XtPointer calldata) { XmDrawingAreaCallbackStruct *cb = calldata; XExposeEvent *e; XmString str; char buf[128]; int x,y,w,h; if (!(cb->reason == XmCR_EXPOSE)) return; e = (XExposeEvent*)cb->event; if (e->count) return; if (!ps.gc) ps.gc = XCreateGC(dpy,XtWindow(app_shell),0,NULL); w = DSCALED(ps.pwidth); h = DSCALED(ps.pheight); x = (DRAW_SIZE-w) / 2; y = (DRAW_SIZE-h) / 2; XDrawRectangle(dpy,XtWindow(widget),ps.gc, x,y,w,h); w = DSCALED(ps.width); h = DSCALED(ps.height); x += DSCALED(ps.xcenter - ps.width/2); y += DSCALED(ps.ycenter - ps.height/2); XFillRectangle(dpy,XtWindow(widget),ps.gc, x,y,w,h); sprintf(buf,"%d dpi",ps.iwidth * 72 / ps.width); str = XmStringGenerate(buf, NULL, XmMULTIBYTE_TEXT, NULL); XtVaSetValues(ps.geo,XmNlabelString,str,NULL); XmStringFree(str); } static void ps_defaults(void) { /* max size, keep aspect ratio */ if (ps.ori == PORTRAIT) { ps.pwidth = formats[ps.format].width; ps.pheight = formats[ps.format].height; } else { ps.pheight = formats[ps.format].width; ps.pwidth = formats[ps.format].height; } if (ps.iwidth * ps.pheight > ps.iheight * ps.pwidth) { ps.mwidth = ps.pwidth; ps.mheight = ps.iheight * ps.mwidth / ps.iwidth; } else { ps.mheight = ps.pheight; ps.mwidth = ps.iwidth * ps.mheight / ps.iheight; } ps.scaling = 0; if (ps.ires) { /* Use image resolution to calculate default scaling factor. * The image will be printed in original size if it fits into * one page */ ps.scaling = ps.iwidth * 72 * 1000 / ps.mwidth / ps.ires; } if (ps.scaling > 1000 || ps.scaling < 1) { /* default: maxpect with some border */ ps.scaling = 1000; while (ps.mwidth * ps.scaling / 1000 + 50 > ps.mwidth || ps.mheight * ps.scaling / 1000 + 50 > ps.mheight) ps.scaling--; } XmScaleSetValue(ps.scale,ps.scaling); ps.width = ps.mwidth * ps.scaling / 1000; ps.height = ps.mheight * ps.scaling / 1000; ps.xcenter = ps.pwidth/2; ps.ycenter = ps.pheight/2; if (XtWindow(ps.draw)) XClearArea(XtDisplay(ps.draw), XtWindow(ps.draw), 0,0,0,0, True); } static void ps_ranges(void) { if (ps.width == 0) ps.width = 1; if (ps.height == 0) ps.height = 1; if (ps.xcenter - ps.width/2 < 0) ps.xcenter = ps.width/2; if (ps.xcenter + ps.width/2 > ps.pwidth) ps.xcenter = ps.pwidth - ps.width/2; if (ps.ycenter - ps.height/2 < 0) ps.ycenter = ps.height/2; if (ps.ycenter + ps.height/2 > ps.pheight) ps.ycenter = ps.pheight - ps.height/2; } static void ps_mouse(Widget widget, XtPointer client_data, XEvent *ev, Boolean *cont) { switch (ev->type) { case ButtonPress: { XButtonEvent *e = (XButtonEvent*)ev; ps.lastx = e->x; ps.lasty = e->y; break; } case MotionNotify: { XMotionEvent *e = (XMotionEvent*)ev; if (e->state & Button1Mask) { ps.xcenter += (e->x - ps.lastx) * DRAW_SCALE; ps.ycenter += (e->y - ps.lasty) * DRAW_SCALE; ps.lastx = e->x; ps.lasty = e->y; } break; default: return; } } ps_ranges(); if (XtWindow(ps.draw)) XClearArea(XtDisplay(ps.draw), XtWindow(ps.draw), 0,0,0,0, True); } static void ps_paper_cb(Widget widget, XtPointer clientdata, XtPointer call_data) { ps.format = (intptr_t)clientdata; ps_defaults(); } static void ps_ori_cb(Widget widget, XtPointer clientdata, XtPointer call_data) { ps.ori = (intptr_t)clientdata; ps_defaults(); } static void ps_scaling_cb(Widget widget, XtPointer clientdata, XtPointer call_data) { XmScaleCallbackStruct *cd = call_data; ps.scaling = cd->value; ps.width = ps.mwidth * ps.scaling / 1000; ps.height = ps.mheight * ps.scaling / 1000; ps_ranges(); if (XtWindow(ps.draw)) XClearArea(XtDisplay(ps.draw), XtWindow(ps.draw), 0,0,0,0, True); } static void ps_button_cb(Widget widget, XtPointer clientdata, XtPointer call_data) { XmSelectionBoxCallbackStruct *cb = call_data; if (XmCR_OK == cb->reason) { do_save_print(); } XtUnmanageChild(ps.shell); } static int ps_conf(Widget parent, struct ida_image *img) { Widget rc,menu,push,opt; Arg args[2]; intptr_t i; if (!ps.shell) { /* build dialog */ ps.shell = XmCreatePromptDialog(parent,"ps",NULL,0); XmdRegisterEditres(XtParent(ps.shell)); XtUnmanageChild(XmSelectionBoxGetChild(ps.shell,XmDIALOG_HELP_BUTTON)); XtUnmanageChild(XmSelectionBoxGetChild(ps.shell,XmDIALOG_SELECTION_LABEL)); XtUnmanageChild(XmSelectionBoxGetChild(ps.shell,XmDIALOG_TEXT)); XtAddCallback(ps.shell,XmNokCallback,ps_button_cb,NULL); XtAddCallback(ps.shell,XmNcancelCallback,ps_button_cb,NULL); rc = XtVaCreateManagedWidget("rc1",xmRowColumnWidgetClass, ps.shell,NULL); ps.draw = XtVaCreateManagedWidget("draw",xmDrawingAreaWidgetClass,rc, XtNwidth,DRAW_SIZE, XtNheight,DRAW_SIZE, NULL); XtAddCallback(ps.draw,XmNexposeCallback,ps_draw,NULL); XtAddEventHandler(ps.draw, ButtonPressMask | ButtonReleaseMask | ButtonMotionMask, False,ps_mouse,NULL); rc = XtVaCreateManagedWidget("rc2",xmRowColumnWidgetClass, rc,NULL); /* paper */ menu = XmCreatePulldownMenu(rc,"paperM",NULL,0); XtSetArg(args[0],XmNsubMenuId,menu); opt = XmCreateOptionMenu(rc,"paper",args,1); XtManageChild(opt); for (i = 0; formats[i].name != NULL; i++) { push = XtVaCreateManagedWidget(formats[i].name,xmPushButtonWidgetClass,menu,NULL); XtAddCallback(push,XmNactivateCallback,ps_paper_cb,(XtPointer)i); } /* orientation */ menu = XmCreatePulldownMenu(rc,"oriM",NULL,0); XtSetArg(args[0],XmNsubMenuId,menu); opt = XmCreateOptionMenu(rc,"ori",args,1); XtManageChild(opt); push = XtVaCreateManagedWidget("portrait",xmPushButtonWidgetClass, menu,NULL); XtAddCallback(push,XmNactivateCallback,ps_ori_cb,(XtPointer)PORTRAIT); push = XtVaCreateManagedWidget("landscape",xmPushButtonWidgetClass, menu,NULL); XtAddCallback(push,XmNactivateCallback,ps_ori_cb,(XtPointer)LANDSCAPE); ps.scale = XtVaCreateManagedWidget("scale",xmScaleWidgetClass,rc,NULL); XtAddCallback(ps.scale,XmNdragCallback,ps_scaling_cb,NULL); XtAddCallback(ps.scale,XmNvalueChangedCallback,ps_scaling_cb,NULL); /* output */ ps.geo = XtVaCreateManagedWidget("geo",xmLabelWidgetClass,rc,NULL); } ps.iwidth = img->i.width; ps.iheight = img->i.height; ps.ires = 0; if (ida->img.i.dpi) ps.ires = ida->img.i.dpi; ps_defaults(); XtManageChild(ps.shell); return 0; } static int ps_write(FILE *fp, struct ida_image *img) { unsigned int width,height,xoff,yoff; unsigned int iwidth,iheight; unsigned int x,y; unsigned char *p; if (ps.ori == PORTRAIT) { iwidth = img->i.width; iheight = img->i.height; width = ps.width; height = ps.height; xoff = ps.xcenter - ps.width/2; yoff = (ps.pheight - ps.ycenter) - ps.height/2; } else{ iwidth = img->i.height; iheight = img->i.width; width = ps.height; height = ps.width; xoff = ps.ycenter - ps.height/2; yoff = ps.xcenter - ps.width/2; } /* PS header */ fprintf(fp,header, /* includes bbox */ xoff,yoff,xoff+width,yoff+height); fprintf(fp,"\n" "/pix %u string def\n" "/grays %u string def\n" "/npixls 0 def\n" "/rgbindx 0 def\n" "\n", img->i.width*3,img->i.width); fwrite(ColorImage,strlen(ColorImage),1,fp); fprintf(fp,"%u %u translate\n",xoff,yoff); fprintf(fp,"%u %u scale\n",width,height); fprintf(fp,"\n" "%u %u 8\n" "[%u 0 0 -%u 0 %u]\n" "{currentfile pix readhexstring pop}\n" "false 3 colorimage\n", iwidth,iheight,iwidth,iheight,iheight); /* image data + ps footer */ if (ps.ori == PORTRAIT) { p = img->data; for (y = 0; y < img->i.height; y++) { for (x = 0; x < img->i.width; x++) { if (0 == (x % 10)) fprintf(fp,"\n"); fprintf(fp,"%02x%02x%02x ",p[0],p[1],p[2]); p += 3; } fprintf(fp,"\n"); } } else { for (x = img->i.width-1; x != -1; x--) { p = img->data + 3*x; for (y = 0; y < img->i.height; y++) { if (0 == (y % 10)) fprintf(fp,"\n"); fprintf(fp,"%02x%02x%02x ",p[0],p[1],p[2]); p += img->i.width*3; } fprintf(fp,"\n"); } } fprintf(fp,footer); return 0; } struct ida_writer ps_writer = { label: "PostScript", ext: { "ps", "eps", NULL}, write: ps_write, conf: ps_conf, }; static void __init init_wr(void) { write_register(&ps_writer); } fbi-2.10/wr/write-tiff.c0000644000175000017500000000342512506525033013205 0ustar jmmjmm#include #include #include #include #include #include #include "readers.h" #include "writers.h" #include "viewer.h" /* ---------------------------------------------------------------------- */ /* save */ static int tiff_write(FILE *fp, struct ida_image *img) { TIFF *TiffHndl; tdata_t buf; unsigned int y; TiffHndl = TIFFFdOpen(fileno(fp),"42.tiff","w"); if (TiffHndl == NULL) return -1; TIFFSetField(TiffHndl, TIFFTAG_IMAGEWIDTH, img->i.width); TIFFSetField(TiffHndl, TIFFTAG_IMAGELENGTH, img->i.height); TIFFSetField(TiffHndl, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); TIFFSetField(TiffHndl, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB); TIFFSetField(TiffHndl, TIFFTAG_BITSPERSAMPLE, 8); TIFFSetField(TiffHndl, TIFFTAG_SAMPLESPERPIXEL, 3); TIFFSetField(TiffHndl, TIFFTAG_ROWSPERSTRIP, 2); TIFFSetField(TiffHndl, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT); #if 0 /* fixme: make this configureable */ TIFFSetField(TiffHndl, TIFFTAG_COMPRESSION, COMPRESSION_LZW); TIFFSetField(TiffHndl, TIFFTAG_PREDICTOR, 2); #endif if (img->i.dpi) { float dpi = img->i.dpi; TIFFSetField(TiffHndl, TIFFTAG_RESOLUTIONUNIT, RESUNIT_INCH); TIFFSetField(TiffHndl, TIFFTAG_XRESOLUTION, dpi); TIFFSetField(TiffHndl, TIFFTAG_YRESOLUTION, dpi); } for (y = 0; y < img->i.height; y++) { buf = img->data + 3*img->i.width*y; TIFFWriteScanline(TiffHndl, buf, y, 0); } TIFFClose(TiffHndl); return 0; } static struct ida_writer tiff_writer = { label: "TIFF", ext: { "tif", "tiff", NULL}, write: tiff_write, }; static void __init init_wr(void) { write_register(&tiff_writer); } fbi-2.10/wr/write-ppm.c0000644000175000017500000000144612506525033013052 0ustar jmmjmm#include #include #include #include #include #include "readers.h" #include "writers.h" #include "viewer.h" /* ---------------------------------------------------------------------- */ /* save */ static int ppm_write(FILE *fp, struct ida_image *img) { fprintf(fp,"P6\n" "# written by ida " VERSION "\n" "# https://www.kraxel.org/blog/linux/fbida/\n" "%d %d\n255\n", img->i.width,img->i.height); fwrite(img->data, img->i.height, 3*img->i.width, fp); return 0; } static struct ida_writer ppm_writer = { label: "PPM", ext: { "ppm", NULL}, write: ppm_write, }; static void __init init_wr(void) { write_register(&ppm_writer); } fbi-2.10/wr/write-jpeg.c0000644000175000017500000000505112506525033013177 0ustar jmmjmm#include #include #include #include #include #include #include "readers.h" #include "writers.h" #include "misc.h" #include #include #include #include #include #include "RegEdit.h" #include "ida.h" #include "viewer.h" /* ---------------------------------------------------------------------- */ /* jpeg writer */ static Widget jpeg_shell; static Widget jpeg_text; static int jpeg_quality = 75; static void jpeg_button_cb(Widget widget, XtPointer clientdata, XtPointer call_data) { XmSelectionBoxCallbackStruct *cb = call_data; if (XmCR_OK == cb->reason) { jpeg_quality = atoi(XmTextGetString(jpeg_text)); do_save_print(); } XtUnmanageChild(jpeg_shell); } static int jpeg_conf(Widget parent, struct ida_image *img) { char tmp[32]; if (!jpeg_shell) { /* build dialog */ jpeg_shell = XmCreatePromptDialog(parent,"jpeg",NULL,0); XmdRegisterEditres(XtParent(jpeg_shell)); XtUnmanageChild(XmSelectionBoxGetChild(jpeg_shell,XmDIALOG_HELP_BUTTON)); jpeg_text = XmSelectionBoxGetChild(jpeg_shell,XmDIALOG_TEXT); XtAddCallback(jpeg_shell,XmNokCallback,jpeg_button_cb,NULL); XtAddCallback(jpeg_shell,XmNcancelCallback,jpeg_button_cb,NULL); } sprintf(tmp,"%d",jpeg_quality); XmTextSetString(jpeg_text,tmp); XtManageChild(jpeg_shell); return 0; } static int jpeg_write(FILE *fp, struct ida_image *img) { struct jpeg_compress_struct cinfo; struct jpeg_error_mgr jerr; unsigned char *line; unsigned int i; cinfo.err = jpeg_std_error(&jerr); jpeg_create_compress(&cinfo); jpeg_stdio_dest(&cinfo, fp); cinfo.image_width = img->i.width; cinfo.image_height = img->i.height; if (img->i.dpi) { cinfo.density_unit = 1; cinfo.X_density = img->i.dpi; cinfo.Y_density = img->i.dpi; } cinfo.input_components = 3; cinfo.in_color_space = JCS_RGB; jpeg_set_defaults(&cinfo); jpeg_set_quality(&cinfo, jpeg_quality, TRUE); jpeg_start_compress(&cinfo, TRUE); for (i = 0, line = img->data; i < img->i.height; i++, line += img->i.width*3) jpeg_write_scanlines(&cinfo, &line, 1); jpeg_finish_compress(&(cinfo)); jpeg_destroy_compress(&(cinfo)); return 0; } struct ida_writer jpeg_writer = { label: "JPEG", ext: { "jpg", "jpeg", NULL}, write: jpeg_write, conf: jpeg_conf, }; static void __init init_wr(void) { write_register(&jpeg_writer); } fbi-2.10/Ida.ad0000644000175000017500000005324512506525033011341 0ustar jmmjmm! ---------------------------------------------------------------------------- ! fonts *renderTable: small *renderTable.fontType: FONT_IS_FONTSET *renderTable.fontName: \ -*-helvetica-medium-r-normal-*-*-140-*-*-p-*-*-*, \ -*-lucida-medium-r-normal-*-*-140-*-*-p-*-*-*, \ -*-liberation sans-medium-r-normal-*-*-140-*-*-p-*-*-*, \ -*-*-medium-r-normal-*-*-140-*-*-p-*-*-*, \ -*-*-medium-r-normal-*-*-160-*-*-p-*-*-*, * *renderTable.small.fontType: FONT_IS_FONTSET *renderTable.small.fontName: \ -*-helvetica-medium-r-normal-*-*-100-*-*-p-*-*-*, \ -*-lucida-medium-r-normal-*-*-100-*-*-p-*-*-*, \ -*-liberation sans-medium-r-normal-*-*-100-*-*-p-*-*-*, \ -*-*-medium-r-normal-*-*-100-*-*-p-*-*-*, \ -*-*-medium-r-normal-*-*-120-*-*-p-*-*-*, * *XmTextField.renderTable: *XmTextField.renderTable.fontType: FONT_IS_FONTSET *XmTextField.renderTable.fontName: \ -*-courier-medium-r-normal-*-*-140-*-*-m-*-*-*, \ -*-lucidatypewriter-medium-r-normal-*-*-140-*-*-m-*-*-*, \ -*-liberation mono-medium-r-normal-*-*-140-*-*-*-*-*-*, \ -*-*-medium-r-normal-*-*-140-*-*-m-*-*-*, \ -*-*-medium-r-normal-*-*-160-*-*-m-*-*-*, * *background: gray77 !*shadowThickness: 2 !*highlightThickness: 1 ! ---------------------------------------------------------------------------- ! image window Ida.geometry: 75x50 !Ida.winGravity: static Ida.view*translations: #override \ space: Next() \n\ osfDelete: Prev() \n\ osfBackSpace: Prev() \n\ Page_Down: NextPage() \n\ Page_Up: PrevPage() \n\ N: NextPage() \n\ ~CtrlP: PrevPage() \n\ KP_Add: Zoom(inc) \n\ KP_Subtract: Zoom(dec) \n\ : Ipc(drag) \n\ : Popup(control) \n\ \ G: Gamma() \n\ F: Browser() \n\ L: Filelist() \n\ CtrlV: Ipc(paste) \n\ AltV: Ipc(paste) \n\ CtrlC: Ipc(copy) \n\ AltC: Ipc(copy) \n\ \ CtrlP: Print() \n\ CtrlL: Load() \n\ CtrlS: Save() \n\ AltS: Sharpe() \n\ ~Alt ~CtrlS: Resize() \n\ plus: Zoom(inc) \n\ minus: Zoom(dec) \n\ U: Undo() \n\ ~Alt ~CtrlC: Filter(crop) \n\ ~Alt ~CtrlV: Filter(flip-vert) \n\ H: Filter(flip-horz) \n\ ~Alt ~ShiftT: Filter(rotate-cw) \n\ ShiftT: Filter(rotate-ccw) \n\ AltT: Rotate() \n\ I: Filter(invert) \n\ ~AltE: Color() \n\ AltE: F3x3(-1,-1,-1,-1,8,-1,-1,-1,-1) \n\ AltB: F3x3(1,1,1,1,1,1,1,1,1, 1,9) \n\ AltM: F3x3(1,0,0,0,0,0,0,0,-1, 0,0,128) \n\ osfHelp: Man(ida) \n\ Q: Exit() Ida.view.VertScrollBar.accelerators: #override \ : IncrementUpOrLeft(Up) \n\ : IncrementDownOrRight(Down)\n\ ~CtrlosfUp: IncrementUpOrLeft(Up) \n\ ~CtrlosfDown: IncrementDownOrRight(Down)\n\ CtrlosfUp: PageUpOrLeft(Up) \n\ CtrlosfDown: PageDownOrRight(Down) Ida.view.HorScrollBar.accelerators: #override \ ~CtrlosfLeft: IncrementUpOrLeft(Left) \n\ ~CtrlosfRight: IncrementDownOrRight(Right)\n\ CtrlosfLeft: PageUpOrLeft(Left) \n\ CtrlosfRight: PageDownOrRight(Right) Ida.view.shadowThickness: 1 Ida.view.scrollingPolicy: AUTOMATIC Ida.view.scrollBarPlacement: BOTTOM_RIGHT Ida.view.scrolledWindowChildType: SCROLL_VERT Ida.view*image.backgroundPixmap: none Ida.view*image.borderWidth: 0 Ida.view*image.highlightThickness: 1 Ida.view*image.highlightColor: red Ida.aboutbox_popup.deleteResponse: DESTROY Ida.aboutbox_popup.title: About ida Ida*aboutbox_popup*messageString: \ ida - image viewer & editor \n\ \n\ (c) 2001,02 Gerd Hoffmann Ida.sorrybox_popup.deleteResponse: DESTROY Ida.noundobox_popup.deleteResponse: DESTROY Ida.noundobox_popup.title: No undo Ida*noundobox_popup*messageString: \ No undo info available, sorry. \n\ You can undo the last step only. ! ---------------------------------------------------------------------------- ! dialog boxes Ida.XmDialogShell.deleteResponse: DESTROY Ida.XmDialogShell*scale.orientation: HORIZONTAL Ida.XmDialogShell*scale.showValue: True Ida.errbox_popup.deleteResponse: UNMAP Ida.errbox_popup.title: Errors Ida.load_popup.deleteResponse: UNMAP Ida.load_popup.title: Load File Ida.save_popup*deleteResponse: UNMAP Ida.save_popup*dialogStyle: DIALOG_PRIMARY_APPLICATION_MODAL Ida.save_popup.title: Save File Ida.save_popup*format.labelString: Image format: Ida.print_popup*deleteResponse: UNMAP Ida.print_popup*dialogStyle: DIALOG_PRIMARY_APPLICATION_MODAL Ida.print_popup.title: Print File Ida.print_popup*selectionLabelString: Print command Ida.print_popup*textString: lpr Ida*ps_popup*rc1.orientation: HORIZONTAL Ida*ps_popup*draw.borderWidth: 1 Ida*ps_popup*draw.background: white Ida*ps_popup*draw.resizePolicy: RESIZE_NONE Ida*ps_popup*scale.titleString: Scaling Ida*ps_popup*scale.minimum: 10 Ida*ps_popup*scale.maximum: 1000 Ida*ps_popup*scale.decimalPoints: 1 Ida*ps_popup.title: PostScript Options Ida*ps_popup*paper.labelString: Paper size: Ida*ps_popup*ori.labelString: Orientation: Ida*jpeg_popup.title: JPEG Options Ida*jpeg_popup*selectionLabelString: Image quality (0 ... 100) Ida.gamma_popup*scale.minimum: 20 Ida.gamma_popup*scale.maximum: 500 Ida.gamma_popup*scale.decimalPoints: 2 Ida.gamma_popup.title: Gamma correction Ida.gamma_popup*selectionLabelString: Gamma value Ida.bright_popup*scale.minimum: -256 Ida.bright_popup*scale.maximum: 256 Ida.bright_popup.title: Adjust bright Ida.bright_popup*selectionLabelString: Bright Ida.contrast_popup*scale.minimum: -128 Ida.contrast_popup*scale.maximum: 512 Ida.contrast_popup.title: Adjust contrast Ida.contrast_popup*selectionLabelString: Contrast Ida.rotate_popup*scale.minimum: -180 Ida.rotate_popup*scale.maximum: 180 Ida.rotate_popup.title: Rotate image Ida.rotate_popup*selectionLabelString: angle Ida.sharpe_popup*scale.minimum: 0 Ida.sharpe_popup*scale.maximum: 100 Ida.sharpe_popup.title: Sharpe image Ida.sharpe_popup*selectionLabelString: value Ida.resize_popup.deleteResponse: DESTROY Ida.resize_popup*rc.adjustMargin: false Ida.resize_popup*rc.rc.orientation: HORIZONTAL Ida.resize_popup*rc.rc.?.indicatorType: ONE_OF_MANY Ida.resize_popup.title: Scale image Ida.resize_popup*lx.labelString: Width (pixels) Ida.resize_popup*ly.labelString: Height (pixels) Ida.resize_popup*lr.labelString: Resolution (dpi) Ida.resize_popup*lock.labelString: Keep aspect ratio Ida.resize_popup*size.labelString: Change size Ida.resize_popup*res.labelString: Change resolution Ida.resize_popup*phys.labelString: Image size ! ---------------------------------------------------------------------------- ! edit colors dialog Ida.color_popup.deleteResponse: DESTROY Ida.color_popup.title: Edit colors Ida.color_popup*hist.labelString: Histograms Ida.color_popup*map.labelString: Maps Ida.color_popup*lock.labelString: Same values for all channels Ida.color_popup*vals.labelString: Show values for channel: Ida.color_popup*valsM.red.labelString: red Ida.color_popup*valsM.green.labelString: green Ida.color_popup*valsM.blue.labelString: blue Ida.color_popup*in.label.labelString: Input range: Ida.color_popup*out.label.labelString: Output range: Ida.color_popup*gamma.label.labelString: Gamma: !Ida.color_popup*white.labelString: FIXME Ida.color_popup*XmForm*leftOffset: 10 Ida.color_popup*XmForm*rightOffset: 10 Ida.color_popup*XmForm*topOffset: 10 Ida.color_popup*XmForm*bottomOffset: 10 Ida.color_popup*XmForm*leftAttachment: ATTACH_WIDGET Ida.color_popup*XmForm*topAttachment: ATTACH_WIDGET Ida.color_popup*XmForm.sep.rightAttachment: ATTACH_FORM Ida.color_popup*XmForm.XmRowColumn.rightAttachment: ATTACH_FORM Ida.color_popup*XmForm.XmRowColumn.orientation: HORIZONTAL Ida.color_popup*XmText.columns: 5 Ida.color_popup*XmDrawingArea.background: white Ida.color_popup*XmDrawingArea.borderWidth: 1 Ida.color_popup*XmDrawingArea.borderColor: black Ida.color_popup*hred.topWidget: hist Ida.color_popup*hgreen.topWidget: hred Ida.color_popup*hblue.topWidget: hgreen Ida.color_popup*map.leftWidget: hred Ida.color_popup*mred.topWidget: hist Ida.color_popup*mred.leftWidget: hred Ida.color_popup*mred.rightAttachment: ATTACH_FORM Ida.color_popup*mgreen.topWidget: mred Ida.color_popup*mgreen.leftWidget: hgreen Ida.color_popup*mgreen.rightAttachment: ATTACH_FORM Ida.color_popup*mblue.topWidget: mgreen Ida.color_popup*mblue.leftWidget: hblue Ida.color_popup*mblue.rightAttachment: ATTACH_FORM Ida.color_popup*lock.topWidget: hblue Ida.color_popup*vals.topWidget: lock Ida.color_popup*in.topWidget: vals Ida.color_popup*out.topWidget: in Ida.color_popup*gamma.topWidget: out Ida.color_popup*pick.topWidget: gamma ! ---------------------------------------------------------------------------- ! control ctrl.title: ida controls ctrl.form.status.labelString: fixme ctrl*XmMenuShell.XmRowColumn.tearOffModel: TEAR_OFF_ENABLED ctrl*tool.orientation: HORIZONTAL ctrl*tool.XmPushButton.shadowThickness: 1 ctrl.toolTipEnable: 1 ctrl.toolTipPostDelay: 2000 ctrl.toolTipPostDuration: 5000 ctrl*TipLabel.foreground: black ctrl*TipLabel.background: lightyellow ctrl*TipShell.borderWidth: 1 ctrl*TipShell.borderColor: black ctrl*tool.XmSeparator.orientation: VERTICAL ctrl*tool.XmSeparator.width: 12 ctrl*tool.XmSeparator.margin: 3 ctrl*tool.XmPushButton.labelType: PIXMAP ctrl*tool.prev.toolTipString: previous file ctrl*tool.prev.labelPixmap: prev ctrl*tool.next.toolTipString: next file ctrl*tool.next.labelPixmap: next ctrl*tool.zoomin.toolTipString: zoom in ctrl*tool.zoomin.labelPixmap: zoomin ctrl*tool.zoomout.toolTipString: zoom out ctrl*tool.zoomout.labelPixmap: zoomout ctrl*tool.flipv.toolTipString: flip vertical ctrl*tool.flipv.labelPixmap: flipv ctrl*tool.fliph.toolTipString: flip horizontal ctrl*tool.fliph.labelPixmap: fliph ctrl*tool.rotccw.toolTipString: turn counter clockwise ctrl*tool.rotccw.labelPixmap: rotccw ctrl*tool.rotcw.toolTipString: turn clockwise ctrl*tool.rotcw.labelPixmap: rotcw ctrl*tool.exit.toolTipString: quit ctrl*tool.exit.labelPixmap: exit ctrl.form*list.visibleItemCount: 12 ctrl.form*list.translations: #override \ space: Next() \n\ osfDelete: Prev() \n\ osfBackSpace: Prev() \n\ KP_Add: Zoom(inc) \n\ KP_Subtract: Zoom(dec) ! file menu ctrl*bar.file.labelString: File ctrl*bar.file.mnemonic: F ctrl*bar*load.labelString: Load image ... ctrl*bar*load.mnemonic: L ctrl*bar*load.acceleratorText: Ctrl+L ctrl*bar*load.accelerator: CtrlL ctrl*bar*save.labelString: Save image ... ctrl*bar*save.mnemonic: S ctrl*bar*save.acceleratorText: Ctrl+S ctrl*bar*save.accelerator: CtrlS ctrl*bar*browse.labelString: File browser ... ctrl*bar*browse.acceleratorText: F ctrl*bar*browse.accelerator: F ctrl*bar*filelist.labelString: File list ... ctrl*bar*filelist.acceleratorText: L ctrl*bar*filelist.accelerator: L ctrl*bar*scan.labelString: Scan ctrl*bar*print.labelString: Print ... ctrl*bar*print.mnemonic: P ctrl*bar*print.acceleratorText: Ctrl+P ctrl*bar*print.accelerator: CtrlP ctrl*bar*quit.labelString: Quit ctrl*bar*quit.mnemonic: Q ctrl*bar*quit.acceleratorText: Q ctrl*bar*quit.accelerator: Q ! edit menu ctrl*bar.edit.labelString: Edit ctrl*bar.edit.mnemonic: E ctrl*bar*undo.labelString: Undo last operation ctrl*bar*undo.mnemonic: U ctrl*bar*undo.acceleratorText: U ctrl*bar*undo.accelerator: U ctrl*bar*copy.labelString: Copy ctrl*bar*copy.acceleratorText: Ctrl+C ctrl*bar*copy.accelerator: CtrlC ctrl*bar*paste.labelString: Paste ctrl*bar*paste.acceleratorText: Ctrl+V ctrl*bar*paste.accelerator: CtrlV ctrl*bar*flipv.labelString: Flip vertical ctrl*bar*flipv.mnemonic: v ctrl*bar*flipv.acceleratorText: V ctrl*bar*flipv.accelerator: V ctrl*bar*fliph.labelString: Flip horizontal ctrl*bar*fliph.mnemonic: h ctrl*bar*fliph.acceleratorText: H ctrl*bar*fliph.accelerator: H ctrl*bar*rotcw.labelString: Turn clockwise ctrl*bar*rotcw.mnemonic: T ctrl*bar*rotcw.acceleratorText: T ctrl*bar*rotcw.accelerator: ~Meta ~ShiftT ctrl*bar*rotccw.labelString: Turn counter clockwise ctrl*bar*rotccw.acceleratorText: Shift+T ctrl*bar*rotccw.accelerator: ShiftT ctrl*bar*invert.labelString: Invert ctrl*bar*invert.mnemonic: I ctrl*bar*invert.acceleratorText: I ctrl*bar*invert.accelerator: I ctrl*bar*crop.labelString: Crop ctrl*bar*crop.mnemonic: C ctrl*bar*crop.acceleratorText: C ctrl*bar*crop.accelerator: C ctrl*bar*acrop.labelString: Autocrop ctrl*bar*acrop.mnemonic: A ctrl*bar*scale.labelString: Scale ... ctrl*bar*scale.mnemonic: S ctrl*bar*scale.acceleratorText: S ctrl*bar*scale.accelerator: ~CtrlS ctrl*bar*rotany.labelString: Rotate ... ctrl*bar*rotany.acceleratorText: Alt+T ctrl*bar*rotany.accelerator: AltT ! filter menu ctrl*bar.op.labelString: Filters ctrl*bar.op.mnemonic: F ctrl*bar*gamma.labelString: Gamma ... ctrl*bar*gamma.mnemonic: G ctrl*bar*gamma.acceleratorText: G ctrl*bar*gamma.accelerator: G ctrl*bar*bright.labelString: Bright ... ctrl*bar*bright.mnemonic: B ctrl*bar*contr.labelString: Contrast ... ctrl*bar*contr.mnemonic: C ctrl*bar*color.labelString: Edit colors ... ctrl*bar*color.mnemonic: E ctrl*bar*color.acceleratorText: E ctrl*bar*color.accelerator: ~AltE ctrl*bar*gray.labelString: Grayscale ctrl*bar*blur.labelString: Blur ctrl*bar*blur.acceleratorText: Alt+B ctrl*bar*blur.accelerator: AltB ctrl*bar*sharpe.labelString: Sharpe ... ctrl*bar*sharpe.acceleratorText: Alt+S ctrl*bar*sharpe.accelerator: AltS ctrl*bar*edge.labelString: Edge detect ctrl*bar*edge.acceleratorText: Alt+E ctrl*bar*edge.accelerator: AltE ctrl*bar*emboss.labelString: Emboss ctrl*bar*emboss.acceleratorText: Alt+M ctrl*bar*emboss.accelerator: Altm ! view menu ctrl*bar.view.labelString: View ctrl*bar.view.mnemonic: V ctrl*bar*prev.labelString: Previous file ctrl*bar*prev.acceleratorText: backspace !ctrl*bar*prev.accelerator: Backspace ctrl*bar*next.labelString: Next file ctrl*bar*next.acceleratorText: space !ctrl*bar*next.accelerator: space ctrl*bar*prevpage.labelString: Previous page ctrl*bar*prevpage.acceleratorText: PageUp !ctrl*bar*prevpage.accelerator: osfPageUp ctrl*bar*nextpage.labelString: Next page ctrl*bar*nextpage.acceleratorText: PageDown !ctrl*bar*nextpage.accelerator: osfPageDown ctrl*bar*zoomin.labelString: Zoom in ctrl*bar*zoomin.acceleratorText: plus ctrl*bar*zoomin.accelerator: plus ctrl*bar*zoomout.labelString: Zoom out ctrl*bar*zoomout.acceleratorText: minus ctrl*bar*zoomout.accelerator: minus ! options menu ctrl*bar.opt.labelString: Options ctrl*bar.opt.mnemonic: O ctrl*bar*pcd.labelString: PhotoCD resolution ctrl*bar*autozoom.labelString: Autozoom ctrl*bar*cfgsave.labelString: Save Options ! options/photocd menu ctrl*bar*pcdM.1.labelString: 192 x 128 ctrl*bar*pcdM.2.labelString: 384 x 256 ctrl*bar*pcdM.3.labelString: 768 x 512 ctrl*bar*pcdM.4.labelString: 1536 x 1024 ctrl*bar*pcdM.5.labelString: 3072 x 2048 ! help menu ctrl*bar.help.labelString: Help ctrl*bar.help.mnemonic: H ctrl*bar*man.labelString: Manual page ... ctrl*bar*man.mnemonic: M ctrl*bar*man.acceleratorText: F1 ctrl*bar*man.accelerator: F1 ctrl*bar*about.labelString: About ... ctrl*bar*about.mnemonic: A ctrl.form.*.leftAttachment: ATTACH_FORM ctrl.form.*.rightAttachment: ATTACH_FORM ctrl.form.tool.topAttachment: ATTACH_WIDGET ctrl.form.tool.topWidget: bar ctrl.form.listSW.topAttachment: ATTACH_WIDGET ctrl.form.listSW.topWidget: tool ctrl.form.listSW.bottomAttachment: ATTACH_WIDGET ctrl.form.listSW.bottomWidget: status ctrl.form.listSW.width: 320 ctrl.form.listSW.height: 240 ctrl.form.status.bottomAttachment: ATTACH_FORM ctrl.form.status.alignment: ALIGNMENT_BEGINNING ! ---------------------------------------------------------------------------- ! man page renderer Ida.man_popup.deleteResponse: DESTROY Ida.man_popup*view.width: 500 Ida.man_popup*view.height: 600 Ida.man_popup*view.scrollingPolicy: AUTOMATIC Ida.man_popup*view.scrollBarPlacement: BOTTOM_RIGHT Ida.man_popup.title: Manual page Ida.man_popup*okLabelString: close window Ida.man_popup*label.labelString: please wait ... Ida.man_popup*label.alignment: ALIGNMENT_BEGINNING Ida.man_popup*label.marginWidth: 5 Ida.man_popup*label.marginHeight: 5 Ida.man_popup*label.renderTable: bold,underline Ida.man_popup*label.renderTable.fontType: FONT_IS_FONTSET Ida.man_popup*label.renderTable.fontName: \ -*-fixed-medium-r-normal--13-*-*-*-*-*-iso8859-*, \ -*-fixed-medium-r-normal-ja-13-*-*-*-*-*-iso10646-1, \ -gnu-unifont-medium-r-normal--16-*-*-*-*-*-*-*,* Ida.man_popup*label.renderTable.bold.fontType: FONT_IS_FONTSET Ida.man_popup*label.renderTable.bold.fontName: \ -*-fixed-bold-r-normal--13-*-*-*-*-*-iso8859-*, \ -*-fixed-medium-r-normal-ja-13-*-*-*-*-*-iso10646-1, \ -gnu-unifont-bold-r-normal--16-*-*-*-*-*-*-*,* Ida.man_popup*label.renderTable.underline.underlineType: SINGLE_LINE ! ---------------------------------------------------------------------------- ! hex viewer Ida.hex_popup.deleteResponse: DESTROY Ida.hex_popup*view.width: 600 Ida.hex_popup*view.height: 600 Ida.hex_popup*view.scrollingPolicy: AUTOMATIC Ida.hex_popup*view.scrollBarPlacement: BOTTOM_RIGHT Ida.hex_popup*label.alignment: ALIGNMENT_BEGINNING Ida.hex_popup*label.marginWidth: 5 Ida.hex_popup*label.marginHeight: 5 Ida.hex_popup*label.renderTable: bold,underline Ida.hex_popup*label.renderTable.fontType: FONT_IS_FONTSET Ida.hex_popup*label.renderTable.fontName: \ -*-fixed-medium-r-normal--13-*-*-*-*-*-iso8859-*, \ -*-fixed-medium-r-normal-ja-13-*-*-*-*-*-iso10646-1, \ -gnu-unifont-medium-r-normal--16-*-*-*-*-*-*-*,* Ida.hex_popup*label.renderTable.bold.fontType: FONT_IS_FONTSET Ida.hex_popup*label.renderTable.bold.fontName: \ -*-fixed-bold-r-normal--13-*-*-*-*-*-iso8859-*, \ -*-fixed-medium-r-normal-ja-13-*-*-*-*-*-iso10646-1, \ -gnu-unifont-bold-r-normal--16-*-*-*-*-*-*-*,* Ida.hex_popup*label.renderTable.underline.underlineType: SINGLE_LINE ! ---------------------------------------------------------------------------- ! file browser browser.geometry: 600x450 browser.form.?.leftAttachment: ATTACH_FORM browser.form.?.rightAttachment: ATTACH_FORM browser.form.scroll.topAttachment: ATTACH_WIDGET browser.form.scroll.topWidget: cbar browser.form.scroll.bottomAttachment: ATTACH_WIDGET browser.form.scroll.bottomWidget: status browser.form.status.bottomAttachment: ATTACH_FORM browser.form.status.alignment: ALIGNMENT_BEGINNING browser.form.scroll.scrollingPolicy: AUTOMATIC browser.form.scroll.scrollBarPlacement: BOTTOM_RIGHT browser.form.scroll.XmScrollBar.highlightThickness: 1 browser.filter_popup.title: Filter browser.filter_popup*selectionLabelString: pattern? browser*comment_popup.title: JPEG Comment browser*comment_popup*selectionLabelString: Please enter/edit the comment here. ! ---------------------------------------------------------------------------- ! file lists filelist.geometry: 300x400 filelist.form.?.leftAttachment: ATTACH_FORM filelist.form.?.rightAttachment: ATTACH_FORM filelist.form.scroll.topAttachment: ATTACH_WIDGET filelist.form.scroll.topWidget: cbar filelist.form.scroll.bottomAttachment: ATTACH_WIDGET filelist.form.scroll.bottomWidget: status filelist.form.status.bottomAttachment: ATTACH_FORM filelist.form.status.alignment: ALIGNMENT_BEGINNING filelist.form.scroll.scrollingPolicy: AUTOMATIC filelist.form.scroll.scrollBarPlacement: BOTTOM_RIGHT filelist.form.scroll.XmScrollBar.highlightThickness: 1 ! ---------------------------------------------------------------------------- ! browser + file list common stuff *container.outlineButtonPolicy: OUTLINE_BUTTON_ABSENT *container.spatialStyle: CELLS *container.spatialResizeModel: GROW_MINOR *container.spatialSnapModel: CENTER *container.detailTabList: 3cm !*container.spatialIncludeModel: APPEND !*container.layoutDirection: LEFT_TO_RIGHT_TOP_TO_BOTTOM !*container.background: gray85 *container.primaryOwnership: XmOWN_NEVER *container.XmIconGadget.highlightColor: darkred *container.XmIconGadget.shadowThickness: 1 ! file menu *cbar.file.labelString: File *cbar.file.mnemonic: F *cbar*new.labelString: New list *cbar*new.mnemonic: N *cbar*load.labelString: Load list ... *cbar*load.mnemonic: L *cbar*save.labelString: Save list *cbar*save.mnemonic: S *cbar*saveas.labelString: Save list as ... *cbar*saveas.mnemonic: a *cbar*close.labelString: Close window *cbar*close.acceleratorText: Q *cbar*close.accelerator: Q ! edit menu *cbar.edit.labelString: Edit *cbar.edit.mnemonic: E *cbar*copy.labelString: Copy *cbar*copy.acceleratorText: Ctrl+C *cbar*copy.accelerator: CtrlC *cbar*paste.labelString: Paste *cbar*paste.acceleratorText: Ctrl+V *cbar*paste.accelerator: CtrlV *cbar*del.labelString: Delete ! view menu *cbar.view.labelString: View *cbar.view.mnemonic: V *cbar*spatial.labelString: Large Icons *cbar*details.labelString: Details *cbar*filter.labelString: Filter ... *cbar*filter.acceleratorText: F *cbar*filter.accelerator: F *cbar*freset.labelString: Reset filter ! jpeg ops menu *cbar.ops.labelString: JPEG *cbar.ops.mnemonic: J *cbar*rotexif.labelString: Auto Rotate (by EXIT Tag) *cbar*rotexif.mnemonic: A *cbar*rotcw.labelString: Rotate Clockwise *cbar*rotccw.labelString: Rotate Counterclockwise *cbar*comment.labelString: Edit Comment ... *cbar*comment.mnemonic: E *cbar*comment.acceleratorText: E *cbar*comment.accelerator: E ! bookmarks *cbar.dirs.labelString: Bookmarks *cbar.dirs.mnemonic: B ! lists *cbar.lists.labelString: Lists *cbar.lists.mnemonic: L fbi-2.10/writers.c0000644000175000017500000000045212506525033012171 0ustar jmmjmm#include #include #include #include "readers.h" #include "writers.h" /* ----------------------------------------------------------------------- */ LIST_HEAD(writers); void write_register(struct ida_writer *writer) { list_add_tail(&writer->list, &writers); } fbi-2.10/x11.h0000644000175000017500000000277112506525033011116 0ustar jmmjmm#define PSEUDOCOLOR 1 #define TRUECOLOR 2 extern int display_type; extern int display_depth; extern XVisualInfo *info; extern int x11_grays; extern unsigned long *x11_map; extern unsigned long x11_lut_red[256]; extern unsigned long x11_lut_green[256]; extern unsigned long x11_lut_blue[256]; extern unsigned long x11_lut_gray[256]; extern unsigned long x11_map_color[256]; extern unsigned long x11_map_gray[64]; #define x11_black x11_map_gray[0] #define x11_gray x11_map_gray[47*x11_grays/64] #define x11_lightgray x11_map_gray[55*x11_grays/64] #define x11_white x11_map_gray[63*x11_grays/64] extern unsigned long x11_red; extern unsigned long x11_green; extern unsigned long x11_blue; extern int have_shmem; int x11_color_init(Widget shell, int *gray); void x11_data_to_ximage(unsigned char *rgb, unsigned char *ximage, int x, int y, int sy, int gray); XImage *x11_create_ximage(Widget shell, int width, int height, void **shm); void x11_destroy_ximage(Widget shell, XImage * ximage, void *shm); Pixmap x11_create_pixmap(Widget shell, unsigned char *data, int width, int height, int gray); #define XPUTIMAGE(dpy,dr,gc,xi,a,b,c,d,w,h) \ if (have_shmem) \ XShmPutImage(dpy,dr,gc,xi,a,b,c,d,w,h,True); \ else \ XPutImage(dpy,dr,gc,xi,a,b,c,d,w,h) fbi-2.10/lut.h0000644000175000017500000000046312506525033011305 0ustar jmmjmmstruct op_map_parm_ch { float gamma; int bottom; int top; int left; int right; }; struct op_map_parm { struct op_map_parm_ch red; struct op_map_parm_ch green; struct op_map_parm_ch blue; }; extern struct op_map_parm_ch op_map_nothing; extern struct ida_op desc_map; fbi-2.10/viewer.c0000644000175000017500000006011712506525033011777 0ustar jmmjmm#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "ida.h" #include "x11.h" #include "dither.h" #include "readers.h" #include "viewer.h" #include "hex.h" #include "idaconfig.h" /* ----------------------------------------------------------------------- */ #define POINTER_NORMAL 0 #define POINTER_BUSY 1 #define POINTER_PICK 2 #define RUBBER_NEW 3 #define RUBBER_MOVE 4 #define RUBBER_X1 5 #define RUBBER_Y1 6 #define RUBBER_X2 7 #define RUBBER_Y2 8 #define RUBBER_RANGE 6 #define RUBBER_INTERVAL 100 #define PROCESS_LINES 16 int debug; Cursor ptrs[POINTER_COUNT]; /* ----------------------------------------------------------------------- */ Pixmap image_to_pixmap(struct ida_image *img) { unsigned char line[256],*src; XImage *ximage; void *shm; Pixmap pix; GC gc; unsigned int x,y; ximage = x11_create_ximage(app_shell, img->i.width, img->i.height, &shm); for (y = 0; y < img->i.height; y++) { src = img->data + 3*y*img->i.width; if (display_type == PSEUDOCOLOR) { dither_line(src, line, y, img->i.width); for (x = 0; x < img->i.width; x++) XPutPixel(ximage, x, y, x11_map[line[x]]); } else { for (x = 0; x < img->i.width; x++, src += 3) { pix = x11_lut_red[src[0]] | x11_lut_green[src[1]] | x11_lut_blue[src[2]]; XPutPixel(ximage, x, y, pix); } } } pix = XCreatePixmap(dpy,XtWindow(app_shell),img->i.width, img->i.height, DefaultDepthOfScreen(XtScreen(app_shell))); gc = XCreateGC(dpy, pix, 0, NULL); XPUTIMAGE(dpy, pix, gc, ximage, 0, 0, 0, 0, img->i.width, img->i.height); XFreeGC(dpy, gc); x11_destroy_ximage(app_shell, ximage, shm); return pix; } /* ----------------------------------------------------------------------- */ int viewer_i2s(int zoom, int val) { if (0 > zoom) return val/(-zoom+1); if (0 < zoom) return val*(zoom+1); return val; } /* ----------------------------------------------------------------------- */ static void viewer_renderline(struct ida_viewer *ida, char *scanline) { unsigned char *src,*dst,*rgb; unsigned long pix; unsigned int x,s,scrline; src = scanline; if (0 == ida->zoom) { /* as-is */ if (display_type == PSEUDOCOLOR) { dst = ida->dither_line; dither_line(src, dst, ida->line, ida->scrwidth); for (x = 0; x < ida->scrwidth; x++, dst++) XPutPixel(ida->ximage, x, ida->line, x11_map[*dst]); } else { for (x = 0; x < ida->scrwidth; x++, src += 3) { pix = x11_lut_red[src[0]] | x11_lut_green[src[1]] | x11_lut_blue[src[2]]; XPutPixel(ida->ximage, x, ida->line, pix); } } } else if (ida->zoom < 0) { /* zoom out */ s = -ida->zoom+1; if (s-1 != (ida->line % s)) return; scrline = ida->line/s; if (display_type == PSEUDOCOLOR) { rgb = ida->rgb_line; for (x = 0; x < ida->scrwidth; x++, rgb += 3, src += 3*s) { rgb[0] = src[0]; rgb[1] = src[1]; rgb[2] = src[2]; } rgb = ida->rgb_line; dst = ida->dither_line; dither_line(rgb, dst, scrline, ida->scrwidth); for (x = 0; x < ida->scrwidth; x++, dst++) XPutPixel(ida->ximage, x, scrline, x11_map[*dst]); } else { #if 0 /* just drop pixels */ for (x = 0; x < ida->scrwidth; x++, src += 3*s) { pix = x11_lut_red[src[0]] | x11_lut_green[src[1]] | x11_lut_blue[src[2]]; XPutPixel(ida->ximage, x, scrline, pix); } #else /* horizontal interpolation (vertical is much harder ...) */ for (x = 0; x < ida->scrwidth; x++, src += 3*s) { int red,green,blue,count,ix; red = 0; green = 0; blue = 0; count = 0; for (ix = 0; ix < 3*s; ix += 3) { red += src[ix+0]; green += src[ix+1]; blue += src[ix+2]; count += 1; } pix = x11_lut_red[red/count] | x11_lut_green[green/count] | x11_lut_blue[blue/count]; XPutPixel(ida->ximage, x, scrline, pix); } #endif } } else { /* zoom in */ s = ida->zoom+1; if (display_type == PSEUDOCOLOR) { rgb = ida->rgb_line; for (x = 0; x < ida->scrwidth; rgb += 3) { rgb[0] = src[0]; rgb[1] = src[1]; rgb[2] = src[2]; x++; if (0 == (x%s)) src += 3; } for (scrline = ida->line*s; scrline < ida->line*s+s; scrline++) { rgb = ida->rgb_line; dst = ida->dither_line; dither_line(rgb, dst, scrline, ida->scrwidth); for (x = 0; x < ida->scrwidth; x++, dst++) XPutPixel(ida->ximage, x, scrline, x11_map[*dst]); } } else { for (scrline = ida->line*s; scrline < ida->line*s+s; scrline++) { src = scanline; for (x = 0; x < ida->scrwidth; src += 3) { unsigned int i; pix = x11_lut_red[src[0]] | x11_lut_green[src[1]] | x11_lut_blue[src[2]]; for (i = 0; i < s; i++, x++) XPutPixel(ida->ximage, x, scrline, pix); } } } } } /* ----------------------------------------------------------------------- */ static void viewer_cleanup(struct ida_viewer *ida) { if (ida->load_read) { ida->load_done(ida->load_data); ida->load_line = 0; ida->load_read = NULL; ida->load_done = NULL; ida->load_data = NULL; } if (ida->op_work) { ida->op_done(ida->op_data); ida->op_line = 0; ida->op_work = NULL; ida->op_done = NULL; ida->op_data = NULL; if (ida->op_src.data) { if (ida->undo.data) { fprintf(stderr,"have undo buffer /* shouldn't happen */"); free(ida->undo.data); } ida->undo = ida->op_src; memset(&ida->op_src,0,sizeof(ida->op_src)); } } } static Boolean viewer_workproc(XtPointer client_data) { struct ida_viewer *ida = client_data; unsigned int start,end; char *scanline; start = ida->line; end = ida->line + ida->steps; if (end > ida->img.i.height) end = ida->img.i.height; /* image loading */ if (ida->load_read) { for (ida->line = start; ida->line < end; ida->line++) { if (ida->load_line > ida->line) continue; scanline = ida->img.data + ida->img.i.width * ida->load_line * 3; ida->load_read(scanline,ida->load_line,ida->load_data); ida->load_line++; } } /* image processing */ if (ida->op_work && 0 == ida->op_preview) { for (ida->line = start; ida->line < end; ida->line++) { if (ida->op_line > ida->line) continue; scanline = ida->img.data + ida->img.i.width * ida->op_line * 3; ida->op_work(&ida->op_src,&ida->op_rect, scanline,ida->op_line,ida->op_data); ida->op_line++; } } /* image rendering */ if (ida->op_work && ida->op_preview) { for (ida->line = start; ida->line < end; ida->line++) { ida->op_line = ida->line; ida->op_work(&ida->img,&ida->op_rect, ida->preview_line,ida->line,ida->op_data); viewer_renderline(ida,ida->preview_line); } } else { for (ida->line = start; ida->line < end; ida->line++) { scanline = ida->img.data + ida->img.i.width * ida->line * 3; viewer_renderline(ida,scanline); } } /* trigger redraw */ XClearArea(XtDisplay(ida->widget), XtWindow(ida->widget), 0, viewer_i2s(ida->zoom,start), ida->scrwidth, viewer_i2s(ida->zoom,ida->steps), True); /* all done ? */ if (ida->line == ida->img.i.height) { viewer_cleanup(ida); ida->wproc = 0; #if 1 if (args.testload) XtCallActionProc(ida->widget,"Next",NULL,NULL,0); #endif return TRUE; } return FALSE; } static void viewer_workstart(struct ida_viewer *ida) { /* (re-) start */ ida->line = 0; if (!ida->wproc) ida->wproc = XtAppAddWorkProc(app_context,viewer_workproc,ida); } static void viewer_workstop(struct ida_viewer *ida) { if (!ida->wproc) return; viewer_cleanup(ida); XtRemoveWorkProc(ida->wproc); ida->wproc = 0; } static void viewer_workfinish(struct ida_viewer *ida) { char *scanline; if (ida->load_read) { for (ida->line = ida->load_line; ida->line < ida->img.i.height;) { scanline = ida->img.data + ida->img.i.width * ida->line * 3; ida->load_read(scanline,ida->load_line,ida->load_data); ida->line++; ida->load_line++; } } if (ida->op_work && 0 == ida->op_preview) { for (ida->line = ida->op_line; ida->line < ida->img.i.height;) { scanline = ida->img.data + ida->img.i.width * ida->line * 3; ida->op_work(&ida->op_src,&ida->op_rect, scanline,ida->op_line,ida->op_data); ida->line++; ida->op_line++; } } viewer_workstop(ida); } /* ----------------------------------------------------------------------- */ static void viewer_new_view(struct ida_viewer *ida) { if (NULL != ida->ximage) x11_destroy_ximage(ida->widget,ida->ximage,ida->ximage_shm); if (NULL != ida->rgb_line) free(ida->rgb_line); if (NULL != ida->dither_line) free(ida->dither_line); if (NULL != ida->preview_line) free(ida->preview_line); ida->scrwidth = viewer_i2s(ida->zoom,ida->img.i.width); ida->scrheight = viewer_i2s(ida->zoom,ida->img.i.height); ida->steps = PROCESS_LINES; if (ida->zoom < 0) while ((ida->steps % (-ida->zoom+1)) != 0) ida->steps++; ida->rgb_line = malloc(ida->scrwidth*3); ida->dither_line = malloc(ida->scrwidth); ida->preview_line = malloc(ida->img.i.width*3); ida->ximage = x11_create_ximage(ida->widget, ida->scrwidth, ida->scrheight, &ida->ximage_shm); if (NULL == ida->ximage) { ida->zoom--; return viewer_new_view(ida); } XtVaSetValues(ida->widget, XtNwidth, ida->scrwidth, XtNheight, ida->scrheight, NULL); viewer_workstart(ida); } static void viewer_timeout(XtPointer client_data, XtIntervalId *id); static int viewer_rubber_draw(struct ida_viewer *ida) { XGCValues values; struct ida_rect r = ida->current; int x,y,w,h; values.function = GXxor; values.foreground = ida->mask; XChangeGC(dpy,ida->wgc,GCFunction|GCForeground,&values); if (r.x1 < r.x2) { x = viewer_i2s(ida->zoom,r.x1); w = viewer_i2s(ida->zoom,r.x2 - r.x1); } else { x = viewer_i2s(ida->zoom,r.x2); w = viewer_i2s(ida->zoom,r.x1 - r.x2); } if (r.y1 < r.y2) { y = viewer_i2s(ida->zoom,r.y1); h = viewer_i2s(ida->zoom,r.y2 - r.y1); } else { y = viewer_i2s(ida->zoom,r.y2); h = viewer_i2s(ida->zoom,r.y1 - r.y2); } if (0 == h && 0 == w) return 0; if (w) w--; if (h) h--; XDrawRectangle(dpy,XtWindow(ida->widget),ida->wgc,x,y,w,h); return 1; } static void viewer_rubber_off(struct ida_viewer *ida) { if (ida->marked) viewer_rubber_draw(ida); ida->marked = 0; if (ida->timer) XtRemoveTimeOut(ida->timer); ida->timer = 0; } static void viewer_rubber_on(struct ida_viewer *ida) { ida->marked = viewer_rubber_draw(ida); if (ida->marked) ida->timer = XtAppAddTimeOut(app_context,RUBBER_INTERVAL, viewer_timeout,ida); } static void viewer_timeout(XtPointer client_data, XtIntervalId *id) { struct ida_viewer *ida = client_data; ida->timer = 0; viewer_rubber_off(ida); ida->mask <<= 1; if ((ida->mask & 0x10) == 0x10) ida->mask |= 0x01; viewer_rubber_on(ida); } static void viewer_redraw(Widget widget, XtPointer client_data, XEvent *ev, Boolean *cont) { struct ida_viewer *ida = client_data; XExposeEvent *event; XGCValues values; if (ev->type != Expose) return; event = (XExposeEvent*)ev; if (NULL == ida->ximage) return; if (event->x + event->width > (int)ida->scrwidth) return; if (event->y + event->height > (int)ida->scrheight) return; if (NULL == ida->wgc) ida->wgc = XCreateGC(XtDisplay(widget), XtWindow(widget), 0, NULL); viewer_rubber_off(ida); values.function = GXcopy; XChangeGC(dpy,ida->wgc,GCFunction,&values); XPUTIMAGE(XtDisplay(ida->widget), XtWindow(widget), ida->wgc, ida->ximage, event->x, event->y, event->x, event->y, event->width, event->height); viewer_rubber_on(ida); } static int viewer_pos2state(struct ida_viewer *ida, int x, int y) { int x1,x2,y1,y2; if (POINTER_PICK == ida->state) return ida->state; x1 = viewer_i2s(ida->zoom,ida->current.x1); x2 = viewer_i2s(ida->zoom,ida->current.x2); y1 = viewer_i2s(ida->zoom,ida->current.y1); y2 = viewer_i2s(ida->zoom,ida->current.y2); if ((x1 < x && x < x2) || (x2 < x && x < x1)) { if (y1-RUBBER_RANGE < y && y < y1+RUBBER_RANGE) return RUBBER_Y1; if (y2-RUBBER_RANGE < y && y < y2+RUBBER_RANGE) return RUBBER_Y2; } if ((y1 < y && y < y2) || (y2 < y && y < y1)) { if (x1-RUBBER_RANGE < x && x < x1+RUBBER_RANGE) return RUBBER_X1; if (x2-RUBBER_RANGE < x && x < x2+RUBBER_RANGE) return RUBBER_X2; } if (((x1 < x && x < x2) || (x2 < x && x < x1)) && ((y1 < y && y < y2) || (y2 < y && y < y1))) return RUBBER_MOVE; return RUBBER_NEW; } static void viewer_mouse(Widget widget, XtPointer client_data, XEvent *ev, Boolean *cont) { struct ida_viewer *ida = client_data; int state = POINTER_NORMAL; unsigned char *pix; int x,y; viewer_rubber_off(ida); switch (ev->type) { case ButtonPress: { XButtonEvent *eb = (XButtonEvent*)ev; if (eb->button != Button1) goto out; ida->state = viewer_pos2state(ida,eb->x,eb->y); switch (ida->state) { case POINTER_PICK: x = viewer_i2s(-ida->zoom,eb->x); y = viewer_i2s(-ida->zoom,eb->y); pix = ida->img.data + ida->img.i.width*y*3 + x*3; ida->pick_cb(x,y,pix,ida->pick_data); ida->pick_cb = NULL; ida->pick_data = NULL; ida->state = POINTER_NORMAL; state = POINTER_NORMAL; break; case RUBBER_NEW: ida->mask = 0x33333333; ida->current.x1 = ida->current.x2 = viewer_i2s(-ida->zoom,eb->x); ida->current.y1 = ida->current.y2 = viewer_i2s(-ida->zoom,eb->y); break; case RUBBER_MOVE: ida->last_x = viewer_i2s(-ida->zoom,eb->x); ida->last_y = viewer_i2s(-ida->zoom,eb->y); break; case RUBBER_X1: ida->current.x1 = viewer_i2s(-ida->zoom,eb->x); break; case RUBBER_Y1: ida->current.y1 = viewer_i2s(-ida->zoom,eb->y); break; case RUBBER_X2: ida->current.x2 = viewer_i2s(-ida->zoom,eb->x); break; case RUBBER_Y2: ida->current.y2 = viewer_i2s(-ida->zoom,eb->y); break; } state = ida->state; break; } case MotionNotify: { XMotionEvent *em = (XMotionEvent*)ev; if (!(em->state & Button1Mask)) { state = viewer_pos2state(ida,em->x,em->y); goto out; } switch (ida->state) { case RUBBER_NEW: ida->current.x2 = viewer_i2s(-ida->zoom,em->x); ida->current.y2 = viewer_i2s(-ida->zoom,em->y); if (em->state & ShiftMask) { /* square selection */ int xlen,ylen; xlen = abs(ida->current.x1 - ida->current.x2); ylen = abs(ida->current.y1 - ida->current.y2); if (ylen > xlen) { if (ida->current.x1 < ida->current.x2) ida->current.x2 -= (xlen - ylen); else ida->current.x2 += (xlen - ylen); } else { if (ida->current.y1 < ida->current.y2) ida->current.y2 -= (ylen - xlen); else ida->current.y2 += (ylen - xlen); } } break; case RUBBER_MOVE: x = viewer_i2s(-ida->zoom,em->x); y = viewer_i2s(-ida->zoom,em->y); ida->current.x1 += (x - ida->last_x); ida->current.x2 += (x - ida->last_x); ida->current.y1 += (y - ida->last_y); ida->current.y2 += (y - ida->last_y); ida->last_x = x; ida->last_y = y; break; case RUBBER_X1: ida->current.x1 = viewer_i2s(-ida->zoom,em->x); break; case RUBBER_Y1: ida->current.y1 = viewer_i2s(-ida->zoom,em->y); break; case RUBBER_X2: ida->current.x2 = viewer_i2s(-ida->zoom,em->x); break; case RUBBER_Y2: ida->current.y2 = viewer_i2s(-ida->zoom,em->y); break; } state = ida->state; break; } case ButtonRelease: { XButtonEvent *eb = (XButtonEvent*)ev; if (eb->button != Button1) goto out; ida->state = POINTER_NORMAL; state = ida->state; break; } } if (ida->current.x1 < 0) ida->current.x1 = 0; if (ida->current.x1 > ida->img.i.width) ida->current.x1 = ida->img.i.width; if (ida->current.x2 < 0) ida->current.x2 = 0; if (ida->current.x2 > ida->img.i.width) ida->current.x2 = ida->img.i.width; if (ida->current.y1 < 0) ida->current.y1 = 0; if (ida->current.y1 > ida->img.i.height) ida->current.y1 = ida->img.i.height; if (ida->current.y2 < 0) ida->current.y2 = 0; if (ida->current.y2 > ida->img.i.height) ida->current.y2 = ida->img.i.height; out: XDefineCursor(dpy, XtWindow(widget), ptrs[state]); viewer_rubber_on(ida); } /* ----------------------------------------------------------------------- */ /* public stuff */ void viewer_pick(struct ida_viewer *ida, viewer_pick_cb cb, XtPointer data) { if (POINTER_NORMAL != ida->state) return; if (debug) fprintf(stderr,"viewer_pick\n"); ida->state = POINTER_PICK; ida->pick_cb = cb; ida->pick_data = data; } void viewer_unpick(struct ida_viewer *ida) { if (POINTER_PICK != ida->state) return; if (debug) fprintf(stderr,"viewer_unpick\n"); ida->state = POINTER_NORMAL; ida->pick_cb = NULL; ida->pick_data = NULL; } void viewer_autozoom(struct ida_viewer *ida) { if (GET_AUTOZOOM()) { ida->zoom = 0; while (XtScreen(ida->widget)->width < viewer_i2s(ida->zoom,ida->img.i.width) || XtScreen(ida->widget)->height < viewer_i2s(ida->zoom,ida->img.i.height)) ida->zoom--; } viewer_new_view(ida); } void viewer_setzoom(struct ida_viewer *ida, int zoom) { ida->zoom = zoom; viewer_new_view(ida); } static void viewer_op_rect(struct ida_viewer *ida) { if (ida->current.x1 == ida->current.x2 && ida->current.y1 == ida->current.y2) { /* full image */ ida->op_rect.x1 = 0; ida->op_rect.x2 = ida->img.i.width; ida->op_rect.y1 = 0; ida->op_rect.y2 = ida->img.i.height; return; } else { /* have selection */ if (ida->current.x1 < ida->current.x2) { ida->op_rect.x1 = ida->current.x1; ida->op_rect.x2 = ida->current.x2; } else { ida->op_rect.x1 = ida->current.x2; ida->op_rect.x2 = ida->current.x1; } if (ida->current.y1 < ida->current.y2) { ida->op_rect.y1 = ida->current.y1; ida->op_rect.y2 = ida->current.y2; } else { ida->op_rect.y1 = ida->current.y2; ida->op_rect.y2 = ida->current.y1; } } } int viewer_start_op(struct ida_viewer *ida, struct ida_op *op, void *parm) { struct ida_image dst; ptr_busy(); viewer_workfinish(ida); viewer_rubber_off(ida); /* try init */ viewer_op_rect(ida); if (debug) fprintf(stderr,"viewer_start_op: init %s(%p)\n",op->name,parm); ida->op_data = op->init(&ida->img,&ida->op_rect,&dst.i,parm); ptr_idle(); if (NULL == ida->op_data) return -1; dst.data = malloc(dst.i.width * dst.i.height * 3); /* prepare background processing */ if (ida->undo.data) { free(ida->undo.data); memset(&ida->undo,0,sizeof(ida->undo)); } if (ida->op_src.data) { fprintf(stderr,"have op_src buffer /* shouldn't happen */"); free(ida->op_src.data); } ida->op_src = ida->img; ida->img = dst; ida->op_line = 0; ida->op_work = op->work; ida->op_done = op->done; ida->op_preview = 0; if (ida->op_src.i.width != ida->img.i.width || ida->op_src.i.height != ida->img.i.height) { memset(&ida->current,0,sizeof(ida->current)); viewer_autozoom(ida); } else viewer_new_view(ida); return 0; } int viewer_undo(struct ida_viewer *ida) { int resize; viewer_workfinish(ida); if (NULL == ida->undo.data) return -1; viewer_rubber_off(ida); memset(&ida->current,0,sizeof(ida->current)); resize = (ida->undo.i.width != ida->img.i.width || ida->undo.i.height != ida->img.i.height); free(ida->img.data); ida->img = ida->undo; memset(&ida->undo,0,sizeof(ida->undo)); if (resize) viewer_autozoom(ida); else viewer_new_view(ida); return 0; } int viewer_start_preview(struct ida_viewer *ida, struct ida_op *op, void *parm) { struct ida_image dst; viewer_workfinish(ida); /* try init */ viewer_op_rect(ida); ida->op_data = op->init(&ida->img,&ida->op_rect,&dst.i,parm); if (NULL == ida->op_data) return -1; /* prepare background preview */ ida->op_line = 0; ida->op_work = op->work; ida->op_done = op->done; ida->op_preview = 1; viewer_workstart(ida); return 0; } int viewer_cancel_preview(struct ida_viewer *ida) { viewer_workstop(ida); viewer_workstart(ida); return 0; } int viewer_loader_start(struct ida_viewer *ida, struct ida_loader *loader, FILE *fp, char *filename, unsigned int page) { struct ida_image_info info; void *data; /* init loader */ ptr_busy(); memset(&info,0,sizeof(info)); data = loader->init(fp,filename,page,&info,0); ptr_idle(); if (NULL == data) { fprintf(stderr,"loading %s [%s] FAILED\n",filename,loader->name); if (fp) hex_display(filename); return -1; } /* ok, going to load new image */ viewer_workstop(ida); viewer_rubber_off(ida); memset(&ida->current,0,sizeof(ida->current)); if (ida->undo.data) { free(ida->undo.data); memset(&ida->undo,0,sizeof(ida->undo)); } if (NULL != ida->img.data) free(ida->img.data); ida->file = filename; ida->img.i = info; ida->img.data = malloc(ida->img.i.width * ida->img.i.height * 3); /* prepare background loading */ ida->load_line = 0; ida->load_read = loader->read; ida->load_done = loader->done; ida->load_data = data; viewer_autozoom(ida); return info.npages; } int viewer_loadimage(struct ida_viewer *ida, char *filename, unsigned int page) { struct list_head *item; struct ida_loader *loader; char blk[512]; FILE *fp; if (NULL == (fp = fopen(filename, "r"))) { fprintf(stderr,"fopen %s: %s\n",filename,strerror(errno)); return -1; } if (debug) fprintf(stderr,"load: %s\n",filename); memset(blk,0,sizeof(blk)); fread(blk,1,sizeof(blk),fp); rewind(fp); /* pick loader */ list_for_each(item,&loaders) { loader = list_entry(item, struct ida_loader, list); #if 0 if (NULL == loader->magic) break; #else if (NULL == loader->magic) continue; #endif if (0 == memcmp(blk+loader->moff,loader->magic,loader->mlen)) return viewer_loader_start(ida,loader,fp,filename,page); } fprintf(stderr,"%s: unknown format\n",filename); hex_display(filename); fclose(fp); return -1; } int viewer_setimage(struct ida_viewer *ida, struct ida_image *img, char *name) { /* ok, going to load new image */ viewer_workstop(ida); viewer_rubber_off(ida); memset(&ida->current,0,sizeof(ida->current)); if (ida->undo.data) { free(ida->undo.data); memset(&ida->undo,0,sizeof(ida->undo)); } if (NULL != ida->img.data) free(ida->img.data); ida->file = name; ida->img = *img; viewer_autozoom(ida); return 0; } struct ida_viewer* viewer_init(Widget widget) { Colormap cmap = DefaultColormapOfScreen(XtScreen(widget)); struct ida_viewer *ida; XColor white,red,dummy; unsigned int i; ida = malloc(sizeof(*ida)); memset(ida,0,sizeof(*ida)); ida->widget = widget; XtAddEventHandler(widget,ExposureMask,False,viewer_redraw,ida); XtAddEventHandler(widget, ButtonPressMask | ButtonReleaseMask | PointerMotionMask, False,viewer_mouse,ida); ptrs[POINTER_NORMAL] = XCreateFontCursor(dpy,XC_left_ptr); ptrs[POINTER_BUSY] = XCreateFontCursor(dpy,XC_watch); ptrs[POINTER_PICK] = XCreateFontCursor(dpy,XC_tcross); ptrs[RUBBER_NEW] = XCreateFontCursor(dpy,XC_left_ptr); ptrs[RUBBER_MOVE] = XCreateFontCursor(dpy,XC_fleur); ptrs[RUBBER_X1] = XCreateFontCursor(dpy,XC_sb_h_double_arrow); ptrs[RUBBER_X2] = XCreateFontCursor(dpy,XC_sb_h_double_arrow); ptrs[RUBBER_Y1] = XCreateFontCursor(dpy,XC_sb_v_double_arrow); ptrs[RUBBER_Y2] = XCreateFontCursor(dpy,XC_sb_v_double_arrow); if (XAllocNamedColor(dpy,cmap,"white",&white,&dummy) && XAllocNamedColor(dpy,cmap,"red",&red,&dummy)) for (i = 0; i < sizeof(ptrs)/sizeof(Cursor); i++) XRecolorCursor(dpy,ptrs[i],&red,&white); return ida; } fbi-2.10/fbgs.man.fr0000644000175000017500000000547012506525033012357 0ustar jmmjmm.TH FBGS 1 "(c) 1999\-2012 Gerd Hoffmann" "FBGS 2.09" "Visionneuse PostScript/pdf pour la console framebuffer de Linux" \# \# .SH NOM fbgs \- Visionneuse PostScript/pdf du pauvre pour la console framebuffer de Linux. \# \# .SH SYNOPSIS \fBfbgs\fP\ [\fB\-l\fP|\fB\-xl\fP|\fB\-xxl\fP|\fB\-r\fP \fIn\fP]\ [\fB\-c\fP]\ [\fB\-b\fP]\ [\fB\-p\fP\ \fImotdepasse\fP]\ [\fB\--fp\fP\ \fInuméro\fP]\ [\fB\--lp\fP\ \fInuméro\fP]\ [\fIfbi\ options\fP]\ \fIfichier\fP \# \# .SH DESCRIPTION .BR Fbgs est un simple script qui prend un fichier \fIPostScript\fP (PS) ou \fIPortable Document Format\fP (PDF) en entrée, rend les pages en utilisant .BR gs (1) \- GhostScript \- dans un répertoire temporaire et enfin appelle .BR fbi (1) pour les afficher. .SH OPTIONS .BR Fbgs accepte toutes les options de .BR fbi (1) (qu'il lui passe), à l'exception de : store, list, text, (no)comments, e, (no)edit, (no)backup, (no)preserve, (no)readahead, cachemem, blend. .P En plus vous pouvez spécifier : .TP .B -h, --help Afficher le résumé des commandes (remplace l'option fbi). .TP .B -b, --bell Émettre un bip lorsque le document est prêt. .TP .B -c, --color Pour rendre les pages en couleur (Noir et blanc par défaut). .TP .B -l Pour rendre les pages avec une résolution de 100 dpi (75 par défaut). .TP .B -xl Pour rendre les pages avec une résolution de 120 dpi. .TP .B -xxl Pour rendre les pages avec une résolution de 150 dpi. .TP .BI "-r" "\ n" ", --resolution" "\ n" Pour rendre les pages avec une résolution de \fIn\fP dpi (remplace l'option fbi). .TP .BI "-fp" "\ numéro" ", --firstpage" "\ numéro" Commencer à interpréter après la page du document désigné par le \fInuméro\fP. .TP .BI "-lp" "\ numéro" ", --lastpage" "\ numéro" Arrêter d'interpréter après la page du document désigné par le \fInuméro\fP. .TP .BI "-p" "\ motdepasse" ", --password" "\ motdepasse" Vous pouvez utiliser cette option si votre fichier PDF nécessite un \fImotdepasse\fP. \# \# .SH "VOIR AUSSI" .BR fbi (1), .BR gs (1) \# \# .SH TRADUCTEUR Stéphane Aulery .BR \# \# .SH AUTEUR Gerd Hoffmann .BR \# \# .SH COPYRIGHT Copyright (c) 1999-2012 Gerd Hoffmann .P 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. .P 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. .P 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., 675 Mass Ave, Cambridge, MA 02139, USA. fbi-2.10/ida.h0000644000175000017500000000126612506525033011240 0ustar jmmjmmstruct ARGS { Boolean debug; Boolean help; Boolean testload; }; extern struct ARGS args; extern unsigned int pcd_res; extern Widget app_shell; extern XtAppContext app_context; extern Display *dpy; extern struct ida_viewer *ida; void action_cb(Widget widget, XtPointer clientdata, XtPointer call_data); void destroy_cb(Widget widget, XtPointer clientdata, XtPointer call_data); void ptr_register(Widget widget); void ptr_unregister(Widget widget); void ptr_busy(void); void ptr_idle(void); void do_save_print(void); void resize_shell(void); char* load_tmpfile(char *base); void new_file(char *name, int complain); fbi-2.10/writers.h0000644000175000017500000000053412506525033012177 0ustar jmmjmm#include "list.h" #include /* save image files */ struct ida_writer { char *label; char *ext[8]; int (*write)(FILE *fp, struct ida_image *img); int (*conf)(Widget widget, struct ida_image *img); struct list_head list; }; extern struct list_head writers; void write_register(struct ida_writer *writer); fbi-2.10/mallard_48.xpm0000644000175000017500000000672112506525033013010 0ustar jmmjmm/* XPM */ static char *mallard_48[] = { /* columns rows colors chars-per-pixel */ "48 48 45 1 ", " c #15FF0C300C32", ". c #1AB911171118", "X c #1C4D12B912BA", "o c #1F7415FD15FE", "O c #3D3E1E65183B", "+ c #006232730FBC", "@ c #03003C8D1368", "# c #28E91FCB1FCB", "$ c #2BDA23B92318", "% c #3ABF27ED2436", "& c #383F31743031", "* c #3CFA365B3518", "= c #41B43B4139FE", "- c #43AA3DE03C31", "; c #647E309B2445", ": c #059F46A81714", "> c #0ADC5ADD1E6D", ", c #25BC6F572C95", "< c #41E36F160F85", "1 c #5F7F43A93C3B", "2 c #5CFF4D314836", "3 c #5A8056B85431", "4 c #67E461DA618E", "5 c #7E28978307F5", "6 c #409C83D13ABD", "7 c #8365ABB80F4D", "8 c #FBEEFC94002E", "9 c #8AFF86178618", "0 c #8030993987DD", "q c #9A989691965E", "w c #B23E984D9222", "e c #82CFA3538B8A", "r c #856DAD6E8F36", "t c #A6DFA3E9A351", "y c #C78BBE02BB9D", "u c #C57FC30BC30C", "i c #D36FD1F4D1A8", "p c #E838D81BD3EA", "a c #E3C5DF00DDCE", "s c #EE2AE214DEEF", "d c #E9B7E8F9E8D3", "f c #F41BEC0DE9F4", "g c #FA0DF606F4FA", "h c white", "j c None", /* pixels */ "jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj", "jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj", "jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj", "jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj", "jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj", "jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj", "jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj", "jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj", "jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj", "jjjjjjjjjj+++++jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj", "jjjjjjjjj+++++++jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj", "jjjjjjjj+++++++++jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj", "jjjjjjj+++++>>>>:+jjjjjjjjjjjjjjjjjjjjjjjjjjjjjj", "jjjjjj7<:::+++>>:+jjjjjjjjjjjjjjjjjjjjjjjjjjjjjj", "jjjjjj8<>>>>>6,>:+jjjjjjjjjjjjjjjjjjjjjjjjjjjjjj", "jjjjj88886,>>>,>:+jjjjjjjjjjjjjjjjjjjjjjjjjjjjjj", "jjjj88o886,>>>>:@+jjjjjjjjjjjjjjjjjjjjjjjjjjjjjj", "jjj8888886,>>>>+++jjjjjjjjjjjjjjjjjjjjjjjjjjjjjj", "j888888jj>:++++++jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj", "88888jjjjj6::::>6jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj", "888jjjjjjj66,,,6hjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj", "jjjjjjjjjjhhhhhhijjjjiiiiiiiiiijjjjjjjjjjjjjjjjj", "jjjjjjjjj3hhhhhhddiii1;;ooooooiiiiiijjjjj j jjj", "jjjjjjjjooo33fffff1i;i133333####oooiiiiiij jj jj", "jjjjjjjo#ooo333p1ii;itihhhhhhhhhi o*ijj j3 h9", "jjjjjjoooooo12;ps1ii1hihhhhhhhhhhhhi** oi 9uh", "jjjjj #o o#;131ppsssffhhhsssssiiiiioooi o3hhj", "jjjj O O;;1hhhhpsffffhfffiiiiiio oi o#tihhjj", "jjj .o %11dhhhhfffffffspi33321=*&&&& ooojjjj", "jjj oO &3hhhhhhhhhffffpp333333333hhhhhhhjjjjj", "jjj o OO &3hhhhhhhhhhhhhhhhhhhhhhhhhhhhjjjjjjjj", "jjj . O. &3hhhhhhhhhhhhhhhhhhhhhhhhhhhjjjjjjjjj", "jjj &3hhhhhhhhhhhhhhhhhhhhhhhhhhjjjjjjjjjj", "jjj o Oo &3hhhhhhhhhhhhhhhhhhhhhhjjjjjjjjjjjjjj", "jjjjX o. &3hhhhhhhhhhhhhhhhhhwwwjjjjjjjjjjjjjjj", "jjjjjj &3hhhhhhhhhhhjjjjjjj;;;jjjjjjjjjjjjjjj", "jjjjjjjjjjjjjjjjjjjjjjjjjjjj;;jjjjjjjjjjjjjjjjjj", "jjjjjjjjjjjjjjjjjjjjjjjjjjj;;;jjjjjjjjjjjjjjjjjj", "jjjjjjjjjjjjjjjjjjjjjjjjjjj;;;jjjjjjjjjjjjjjjjjj", "jjjjjjjjjjjjjjjjjjjjjjjjjjjjj;;;;;;jjjjjjjjjjjjj", "jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj;;;;;jjjjjjjjjjjj", "jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj;;;;jjjjjjjjjjjj", "jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj", "jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj", "jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj", "jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj", "jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj", "jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj" }; fbi-2.10/fb-gui.h0000644000175000017500000000205512506525033011651 0ustar jmmjmm#include #include FT_FREETYPE_H #include FT_GLYPH_H extern int visible; void shadow_render(void); void shadow_clear_lines(int first, int last); void shadow_clear(void); void shadow_set_dirty(void); void shadow_set_palette(int fd); void shadow_init(void); void shadow_fini(void); void shadow_draw_line(int x1, int x2, int y1,int y2); void shadow_draw_rect(int x1, int x2, int y1,int y2); void shadow_draw_rgbdata(int x, int y, int pixels, unsigned char *rgb); void shadow_merge_rgbdata(int x, int y, int pixels, int weight, unsigned char *rgb); void shadow_darkify(int x1, int x2, int y1,int y2, int percent); void shadow_reverse(int x1, int x2, int y1,int y2); int shadow_draw_string(FT_Face face, int x, int y, wchar_t *str, int align); void shadow_draw_string_cursor(FT_Face face, int x, int y, wchar_t *str, int pos); void shadow_draw_text_box(FT_Face face, int x, int y, int percent, wchar_t *lines[], unsigned int count); void font_init(void); FT_Face font_open(char *fcname); void fb_clear_mem(void); void fb_clear_screen(void); fbi-2.10/jpeg/0000755000175000017500000000000012506525033011252 5ustar jmmjmmfbi-2.10/jpeg/README0000644000175000017500000000030612506525033012131 0ustar jmmjmmsome source files copyed over from The Independent JPEG Group's JPEG software There is a subdirectory for each JPEG_LIB_VERSION to handle incompatible data structures of the jpeg library versions. fbi-2.10/jpeg/80/0000755000175000017500000000000012506525033011501 5ustar jmmjmmfbi-2.10/jpeg/80/transupp.c0000644000175000017500000015677612506525033013547 0ustar jmmjmm/* * transupp.c * * Copyright (C) 1997-2009, Thomas G. Lane, Guido Vollbeding. * This file is part of the Independent JPEG Group's software. * For conditions of distribution and use, see the accompanying README file. * * This file contains image transformation routines and other utility code * used by the jpegtran sample application. These are NOT part of the core * JPEG library. But we keep these routines separate from jpegtran.c to * ease the task of maintaining jpegtran-like programs that have other user * interfaces. */ /* Although this file really shouldn't have access to the library internals, * it's helpful to let it call jround_up() and jcopy_block_row(). */ #define JPEG_INTERNALS #include "jinclude.h" #include "jpeglib.h" #include "transupp.h" /* My own external interface */ #include /* to declare isdigit() */ #if TRANSFORMS_SUPPORTED /* * Lossless image transformation routines. These routines work on DCT * coefficient arrays and thus do not require any lossy decompression * or recompression of the image. * Thanks to Guido Vollbeding for the initial design and code of this feature, * and to Ben Jackson for introducing the cropping feature. * * Horizontal flipping is done in-place, using a single top-to-bottom * pass through the virtual source array. It will thus be much the * fastest option for images larger than main memory. * * The other routines require a set of destination virtual arrays, so they * need twice as much memory as jpegtran normally does. The destination * arrays are always written in normal scan order (top to bottom) because * the virtual array manager expects this. The source arrays will be scanned * in the corresponding order, which means multiple passes through the source * arrays for most of the transforms. That could result in much thrashing * if the image is larger than main memory. * * If cropping or trimming is involved, the destination arrays may be smaller * than the source arrays. Note it is not possible to do horizontal flip * in-place when a nonzero Y crop offset is specified, since we'd have to move * data from one block row to another but the virtual array manager doesn't * guarantee we can touch more than one row at a time. So in that case, * we have to use a separate destination array. * * Some notes about the operating environment of the individual transform * routines: * 1. Both the source and destination virtual arrays are allocated from the * source JPEG object, and therefore should be manipulated by calling the * source's memory manager. * 2. The destination's component count should be used. It may be smaller * than the source's when forcing to grayscale. * 3. Likewise the destination's sampling factors should be used. When * forcing to grayscale the destination's sampling factors will be all 1, * and we may as well take that as the effective iMCU size. * 4. When "trim" is in effect, the destination's dimensions will be the * trimmed values but the source's will be untrimmed. * 5. When "crop" is in effect, the destination's dimensions will be the * cropped values but the source's will be uncropped. Each transform * routine is responsible for picking up source data starting at the * correct X and Y offset for the crop region. (The X and Y offsets * passed to the transform routines are measured in iMCU blocks of the * destination.) * 6. All the routines assume that the source and destination buffers are * padded out to a full iMCU boundary. This is true, although for the * source buffer it is an undocumented property of jdcoefct.c. */ LOCAL(void) do_crop (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, jvirt_barray_ptr *src_coef_arrays, jvirt_barray_ptr *dst_coef_arrays) /* Crop. This is only used when no rotate/flip is requested with the crop. */ { JDIMENSION dst_blk_y, x_crop_blocks, y_crop_blocks; int ci, offset_y; JBLOCKARRAY src_buffer, dst_buffer; jpeg_component_info *compptr; /* We simply have to copy the right amount of data (the destination's * image size) starting at the given X and Y offsets in the source. */ for (ci = 0; ci < dstinfo->num_components; ci++) { compptr = dstinfo->comp_info + ci; x_crop_blocks = x_crop_offset * compptr->h_samp_factor; y_crop_blocks = y_crop_offset * compptr->v_samp_factor; for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; dst_blk_y += compptr->v_samp_factor) { dst_buffer = (*srcinfo->mem->access_virt_barray) ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y, (JDIMENSION) compptr->v_samp_factor, TRUE); src_buffer = (*srcinfo->mem->access_virt_barray) ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_y + y_crop_blocks, (JDIMENSION) compptr->v_samp_factor, FALSE); for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { jcopy_block_row(src_buffer[offset_y] + x_crop_blocks, dst_buffer[offset_y], compptr->width_in_blocks); } } } } LOCAL(void) do_flip_h_no_crop (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, JDIMENSION x_crop_offset, jvirt_barray_ptr *src_coef_arrays) /* Horizontal flip; done in-place, so no separate dest array is required. * NB: this only works when y_crop_offset is zero. */ { JDIMENSION MCU_cols, comp_width, blk_x, blk_y, x_crop_blocks; int ci, k, offset_y; JBLOCKARRAY buffer; JCOEFPTR ptr1, ptr2; JCOEF temp1, temp2; jpeg_component_info *compptr; /* Horizontal mirroring of DCT blocks is accomplished by swapping * pairs of blocks in-place. Within a DCT block, we perform horizontal * mirroring by changing the signs of odd-numbered columns. * Partial iMCUs at the right edge are left untouched. */ MCU_cols = srcinfo->output_width / (dstinfo->max_h_samp_factor * dstinfo->min_DCT_h_scaled_size); for (ci = 0; ci < dstinfo->num_components; ci++) { compptr = dstinfo->comp_info + ci; comp_width = MCU_cols * compptr->h_samp_factor; x_crop_blocks = x_crop_offset * compptr->h_samp_factor; for (blk_y = 0; blk_y < compptr->height_in_blocks; blk_y += compptr->v_samp_factor) { buffer = (*srcinfo->mem->access_virt_barray) ((j_common_ptr) srcinfo, src_coef_arrays[ci], blk_y, (JDIMENSION) compptr->v_samp_factor, TRUE); for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { /* Do the mirroring */ for (blk_x = 0; blk_x * 2 < comp_width; blk_x++) { ptr1 = buffer[offset_y][blk_x]; ptr2 = buffer[offset_y][comp_width - blk_x - 1]; /* this unrolled loop doesn't need to know which row it's on... */ for (k = 0; k < DCTSIZE2; k += 2) { temp1 = *ptr1; /* swap even column */ temp2 = *ptr2; *ptr1++ = temp2; *ptr2++ = temp1; temp1 = *ptr1; /* swap odd column with sign change */ temp2 = *ptr2; *ptr1++ = -temp2; *ptr2++ = -temp1; } } if (x_crop_blocks > 0) { /* Now left-justify the portion of the data to be kept. * We can't use a single jcopy_block_row() call because that routine * depends on memcpy(), whose behavior is unspecified for overlapping * source and destination areas. Sigh. */ for (blk_x = 0; blk_x < compptr->width_in_blocks; blk_x++) { jcopy_block_row(buffer[offset_y] + blk_x + x_crop_blocks, buffer[offset_y] + blk_x, (JDIMENSION) 1); } } } } } } LOCAL(void) do_flip_h (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, jvirt_barray_ptr *src_coef_arrays, jvirt_barray_ptr *dst_coef_arrays) /* Horizontal flip in general cropping case */ { JDIMENSION MCU_cols, comp_width, dst_blk_x, dst_blk_y; JDIMENSION x_crop_blocks, y_crop_blocks; int ci, k, offset_y; JBLOCKARRAY src_buffer, dst_buffer; JBLOCKROW src_row_ptr, dst_row_ptr; JCOEFPTR src_ptr, dst_ptr; jpeg_component_info *compptr; /* Here we must output into a separate array because we can't touch * different rows of a single virtual array simultaneously. Otherwise, * this is essentially the same as the routine above. */ MCU_cols = srcinfo->output_width / (dstinfo->max_h_samp_factor * dstinfo->min_DCT_h_scaled_size); for (ci = 0; ci < dstinfo->num_components; ci++) { compptr = dstinfo->comp_info + ci; comp_width = MCU_cols * compptr->h_samp_factor; x_crop_blocks = x_crop_offset * compptr->h_samp_factor; y_crop_blocks = y_crop_offset * compptr->v_samp_factor; for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; dst_blk_y += compptr->v_samp_factor) { dst_buffer = (*srcinfo->mem->access_virt_barray) ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y, (JDIMENSION) compptr->v_samp_factor, TRUE); src_buffer = (*srcinfo->mem->access_virt_barray) ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_y + y_crop_blocks, (JDIMENSION) compptr->v_samp_factor, FALSE); for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { dst_row_ptr = dst_buffer[offset_y]; src_row_ptr = src_buffer[offset_y]; for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; dst_blk_x++) { if (x_crop_blocks + dst_blk_x < comp_width) { /* Do the mirrorable blocks */ dst_ptr = dst_row_ptr[dst_blk_x]; src_ptr = src_row_ptr[comp_width - x_crop_blocks - dst_blk_x - 1]; /* this unrolled loop doesn't need to know which row it's on... */ for (k = 0; k < DCTSIZE2; k += 2) { *dst_ptr++ = *src_ptr++; /* copy even column */ *dst_ptr++ = - *src_ptr++; /* copy odd column with sign change */ } } else { /* Copy last partial block(s) verbatim */ jcopy_block_row(src_row_ptr + dst_blk_x + x_crop_blocks, dst_row_ptr + dst_blk_x, (JDIMENSION) 1); } } } } } } LOCAL(void) do_flip_v (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, jvirt_barray_ptr *src_coef_arrays, jvirt_barray_ptr *dst_coef_arrays) /* Vertical flip */ { JDIMENSION MCU_rows, comp_height, dst_blk_x, dst_blk_y; JDIMENSION x_crop_blocks, y_crop_blocks; int ci, i, j, offset_y; JBLOCKARRAY src_buffer, dst_buffer; JBLOCKROW src_row_ptr, dst_row_ptr; JCOEFPTR src_ptr, dst_ptr; jpeg_component_info *compptr; /* We output into a separate array because we can't touch different * rows of the source virtual array simultaneously. Otherwise, this * is a pretty straightforward analog of horizontal flip. * Within a DCT block, vertical mirroring is done by changing the signs * of odd-numbered rows. * Partial iMCUs at the bottom edge are copied verbatim. */ MCU_rows = srcinfo->output_height / (dstinfo->max_v_samp_factor * dstinfo->min_DCT_v_scaled_size); for (ci = 0; ci < dstinfo->num_components; ci++) { compptr = dstinfo->comp_info + ci; comp_height = MCU_rows * compptr->v_samp_factor; x_crop_blocks = x_crop_offset * compptr->h_samp_factor; y_crop_blocks = y_crop_offset * compptr->v_samp_factor; for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; dst_blk_y += compptr->v_samp_factor) { dst_buffer = (*srcinfo->mem->access_virt_barray) ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y, (JDIMENSION) compptr->v_samp_factor, TRUE); if (y_crop_blocks + dst_blk_y < comp_height) { /* Row is within the mirrorable area. */ src_buffer = (*srcinfo->mem->access_virt_barray) ((j_common_ptr) srcinfo, src_coef_arrays[ci], comp_height - y_crop_blocks - dst_blk_y - (JDIMENSION) compptr->v_samp_factor, (JDIMENSION) compptr->v_samp_factor, FALSE); } else { /* Bottom-edge blocks will be copied verbatim. */ src_buffer = (*srcinfo->mem->access_virt_barray) ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_y + y_crop_blocks, (JDIMENSION) compptr->v_samp_factor, FALSE); } for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { if (y_crop_blocks + dst_blk_y < comp_height) { /* Row is within the mirrorable area. */ dst_row_ptr = dst_buffer[offset_y]; src_row_ptr = src_buffer[compptr->v_samp_factor - offset_y - 1]; src_row_ptr += x_crop_blocks; for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; dst_blk_x++) { dst_ptr = dst_row_ptr[dst_blk_x]; src_ptr = src_row_ptr[dst_blk_x]; for (i = 0; i < DCTSIZE; i += 2) { /* copy even row */ for (j = 0; j < DCTSIZE; j++) *dst_ptr++ = *src_ptr++; /* copy odd row with sign change */ for (j = 0; j < DCTSIZE; j++) *dst_ptr++ = - *src_ptr++; } } } else { /* Just copy row verbatim. */ jcopy_block_row(src_buffer[offset_y] + x_crop_blocks, dst_buffer[offset_y], compptr->width_in_blocks); } } } } } LOCAL(void) do_transpose (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, jvirt_barray_ptr *src_coef_arrays, jvirt_barray_ptr *dst_coef_arrays) /* Transpose source into destination */ { JDIMENSION dst_blk_x, dst_blk_y, x_crop_blocks, y_crop_blocks; int ci, i, j, offset_x, offset_y; JBLOCKARRAY src_buffer, dst_buffer; JCOEFPTR src_ptr, dst_ptr; jpeg_component_info *compptr; /* Transposing pixels within a block just requires transposing the * DCT coefficients. * Partial iMCUs at the edges require no special treatment; we simply * process all the available DCT blocks for every component. */ for (ci = 0; ci < dstinfo->num_components; ci++) { compptr = dstinfo->comp_info + ci; x_crop_blocks = x_crop_offset * compptr->h_samp_factor; y_crop_blocks = y_crop_offset * compptr->v_samp_factor; for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; dst_blk_y += compptr->v_samp_factor) { dst_buffer = (*srcinfo->mem->access_virt_barray) ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y, (JDIMENSION) compptr->v_samp_factor, TRUE); for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; dst_blk_x += compptr->h_samp_factor) { src_buffer = (*srcinfo->mem->access_virt_barray) ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_x + x_crop_blocks, (JDIMENSION) compptr->h_samp_factor, FALSE); for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) { dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x]; src_ptr = src_buffer[offset_x][dst_blk_y + offset_y + y_crop_blocks]; for (i = 0; i < DCTSIZE; i++) for (j = 0; j < DCTSIZE; j++) dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; } } } } } } LOCAL(void) do_rot_90 (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, jvirt_barray_ptr *src_coef_arrays, jvirt_barray_ptr *dst_coef_arrays) /* 90 degree rotation is equivalent to * 1. Transposing the image; * 2. Horizontal mirroring. * These two steps are merged into a single processing routine. */ { JDIMENSION MCU_cols, comp_width, dst_blk_x, dst_blk_y; JDIMENSION x_crop_blocks, y_crop_blocks; int ci, i, j, offset_x, offset_y; JBLOCKARRAY src_buffer, dst_buffer; JCOEFPTR src_ptr, dst_ptr; jpeg_component_info *compptr; /* Because of the horizontal mirror step, we can't process partial iMCUs * at the (output) right edge properly. They just get transposed and * not mirrored. */ MCU_cols = srcinfo->output_height / (dstinfo->max_h_samp_factor * dstinfo->min_DCT_h_scaled_size); for (ci = 0; ci < dstinfo->num_components; ci++) { compptr = dstinfo->comp_info + ci; comp_width = MCU_cols * compptr->h_samp_factor; x_crop_blocks = x_crop_offset * compptr->h_samp_factor; y_crop_blocks = y_crop_offset * compptr->v_samp_factor; for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; dst_blk_y += compptr->v_samp_factor) { dst_buffer = (*srcinfo->mem->access_virt_barray) ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y, (JDIMENSION) compptr->v_samp_factor, TRUE); for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; dst_blk_x += compptr->h_samp_factor) { if (x_crop_blocks + dst_blk_x < comp_width) { /* Block is within the mirrorable area. */ src_buffer = (*srcinfo->mem->access_virt_barray) ((j_common_ptr) srcinfo, src_coef_arrays[ci], comp_width - x_crop_blocks - dst_blk_x - (JDIMENSION) compptr->h_samp_factor, (JDIMENSION) compptr->h_samp_factor, FALSE); } else { /* Edge blocks are transposed but not mirrored. */ src_buffer = (*srcinfo->mem->access_virt_barray) ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_x + x_crop_blocks, (JDIMENSION) compptr->h_samp_factor, FALSE); } for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) { dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x]; if (x_crop_blocks + dst_blk_x < comp_width) { /* Block is within the mirrorable area. */ src_ptr = src_buffer[compptr->h_samp_factor - offset_x - 1] [dst_blk_y + offset_y + y_crop_blocks]; for (i = 0; i < DCTSIZE; i++) { for (j = 0; j < DCTSIZE; j++) dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; i++; for (j = 0; j < DCTSIZE; j++) dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j]; } } else { /* Edge blocks are transposed but not mirrored. */ src_ptr = src_buffer[offset_x] [dst_blk_y + offset_y + y_crop_blocks]; for (i = 0; i < DCTSIZE; i++) for (j = 0; j < DCTSIZE; j++) dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; } } } } } } } LOCAL(void) do_rot_270 (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, jvirt_barray_ptr *src_coef_arrays, jvirt_barray_ptr *dst_coef_arrays) /* 270 degree rotation is equivalent to * 1. Horizontal mirroring; * 2. Transposing the image. * These two steps are merged into a single processing routine. */ { JDIMENSION MCU_rows, comp_height, dst_blk_x, dst_blk_y; JDIMENSION x_crop_blocks, y_crop_blocks; int ci, i, j, offset_x, offset_y; JBLOCKARRAY src_buffer, dst_buffer; JCOEFPTR src_ptr, dst_ptr; jpeg_component_info *compptr; /* Because of the horizontal mirror step, we can't process partial iMCUs * at the (output) bottom edge properly. They just get transposed and * not mirrored. */ MCU_rows = srcinfo->output_width / (dstinfo->max_v_samp_factor * dstinfo->min_DCT_v_scaled_size); for (ci = 0; ci < dstinfo->num_components; ci++) { compptr = dstinfo->comp_info + ci; comp_height = MCU_rows * compptr->v_samp_factor; x_crop_blocks = x_crop_offset * compptr->h_samp_factor; y_crop_blocks = y_crop_offset * compptr->v_samp_factor; for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; dst_blk_y += compptr->v_samp_factor) { dst_buffer = (*srcinfo->mem->access_virt_barray) ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y, (JDIMENSION) compptr->v_samp_factor, TRUE); for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; dst_blk_x += compptr->h_samp_factor) { src_buffer = (*srcinfo->mem->access_virt_barray) ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_x + x_crop_blocks, (JDIMENSION) compptr->h_samp_factor, FALSE); for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) { dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x]; if (y_crop_blocks + dst_blk_y < comp_height) { /* Block is within the mirrorable area. */ src_ptr = src_buffer[offset_x] [comp_height - y_crop_blocks - dst_blk_y - offset_y - 1]; for (i = 0; i < DCTSIZE; i++) { for (j = 0; j < DCTSIZE; j++) { dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; j++; dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j]; } } } else { /* Edge blocks are transposed but not mirrored. */ src_ptr = src_buffer[offset_x] [dst_blk_y + offset_y + y_crop_blocks]; for (i = 0; i < DCTSIZE; i++) for (j = 0; j < DCTSIZE; j++) dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; } } } } } } } LOCAL(void) do_rot_180 (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, jvirt_barray_ptr *src_coef_arrays, jvirt_barray_ptr *dst_coef_arrays) /* 180 degree rotation is equivalent to * 1. Vertical mirroring; * 2. Horizontal mirroring. * These two steps are merged into a single processing routine. */ { JDIMENSION MCU_cols, MCU_rows, comp_width, comp_height, dst_blk_x, dst_blk_y; JDIMENSION x_crop_blocks, y_crop_blocks; int ci, i, j, offset_y; JBLOCKARRAY src_buffer, dst_buffer; JBLOCKROW src_row_ptr, dst_row_ptr; JCOEFPTR src_ptr, dst_ptr; jpeg_component_info *compptr; MCU_cols = srcinfo->output_width / (dstinfo->max_h_samp_factor * dstinfo->min_DCT_h_scaled_size); MCU_rows = srcinfo->output_height / (dstinfo->max_v_samp_factor * dstinfo->min_DCT_v_scaled_size); for (ci = 0; ci < dstinfo->num_components; ci++) { compptr = dstinfo->comp_info + ci; comp_width = MCU_cols * compptr->h_samp_factor; comp_height = MCU_rows * compptr->v_samp_factor; x_crop_blocks = x_crop_offset * compptr->h_samp_factor; y_crop_blocks = y_crop_offset * compptr->v_samp_factor; for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; dst_blk_y += compptr->v_samp_factor) { dst_buffer = (*srcinfo->mem->access_virt_barray) ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y, (JDIMENSION) compptr->v_samp_factor, TRUE); if (y_crop_blocks + dst_blk_y < comp_height) { /* Row is within the vertically mirrorable area. */ src_buffer = (*srcinfo->mem->access_virt_barray) ((j_common_ptr) srcinfo, src_coef_arrays[ci], comp_height - y_crop_blocks - dst_blk_y - (JDIMENSION) compptr->v_samp_factor, (JDIMENSION) compptr->v_samp_factor, FALSE); } else { /* Bottom-edge rows are only mirrored horizontally. */ src_buffer = (*srcinfo->mem->access_virt_barray) ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_y + y_crop_blocks, (JDIMENSION) compptr->v_samp_factor, FALSE); } for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { dst_row_ptr = dst_buffer[offset_y]; if (y_crop_blocks + dst_blk_y < comp_height) { /* Row is within the mirrorable area. */ src_row_ptr = src_buffer[compptr->v_samp_factor - offset_y - 1]; for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; dst_blk_x++) { dst_ptr = dst_row_ptr[dst_blk_x]; if (x_crop_blocks + dst_blk_x < comp_width) { /* Process the blocks that can be mirrored both ways. */ src_ptr = src_row_ptr[comp_width - x_crop_blocks - dst_blk_x - 1]; for (i = 0; i < DCTSIZE; i += 2) { /* For even row, negate every odd column. */ for (j = 0; j < DCTSIZE; j += 2) { *dst_ptr++ = *src_ptr++; *dst_ptr++ = - *src_ptr++; } /* For odd row, negate every even column. */ for (j = 0; j < DCTSIZE; j += 2) { *dst_ptr++ = - *src_ptr++; *dst_ptr++ = *src_ptr++; } } } else { /* Any remaining right-edge blocks are only mirrored vertically. */ src_ptr = src_row_ptr[x_crop_blocks + dst_blk_x]; for (i = 0; i < DCTSIZE; i += 2) { for (j = 0; j < DCTSIZE; j++) *dst_ptr++ = *src_ptr++; for (j = 0; j < DCTSIZE; j++) *dst_ptr++ = - *src_ptr++; } } } } else { /* Remaining rows are just mirrored horizontally. */ src_row_ptr = src_buffer[offset_y]; for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; dst_blk_x++) { if (x_crop_blocks + dst_blk_x < comp_width) { /* Process the blocks that can be mirrored. */ dst_ptr = dst_row_ptr[dst_blk_x]; src_ptr = src_row_ptr[comp_width - x_crop_blocks - dst_blk_x - 1]; for (i = 0; i < DCTSIZE2; i += 2) { *dst_ptr++ = *src_ptr++; *dst_ptr++ = - *src_ptr++; } } else { /* Any remaining right-edge blocks are only copied. */ jcopy_block_row(src_row_ptr + dst_blk_x + x_crop_blocks, dst_row_ptr + dst_blk_x, (JDIMENSION) 1); } } } } } } } LOCAL(void) do_transverse (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, jvirt_barray_ptr *src_coef_arrays, jvirt_barray_ptr *dst_coef_arrays) /* Transverse transpose is equivalent to * 1. 180 degree rotation; * 2. Transposition; * or * 1. Horizontal mirroring; * 2. Transposition; * 3. Horizontal mirroring. * These steps are merged into a single processing routine. */ { JDIMENSION MCU_cols, MCU_rows, comp_width, comp_height, dst_blk_x, dst_blk_y; JDIMENSION x_crop_blocks, y_crop_blocks; int ci, i, j, offset_x, offset_y; JBLOCKARRAY src_buffer, dst_buffer; JCOEFPTR src_ptr, dst_ptr; jpeg_component_info *compptr; MCU_cols = srcinfo->output_height / (dstinfo->max_h_samp_factor * dstinfo->min_DCT_h_scaled_size); MCU_rows = srcinfo->output_width / (dstinfo->max_v_samp_factor * dstinfo->min_DCT_v_scaled_size); for (ci = 0; ci < dstinfo->num_components; ci++) { compptr = dstinfo->comp_info + ci; comp_width = MCU_cols * compptr->h_samp_factor; comp_height = MCU_rows * compptr->v_samp_factor; x_crop_blocks = x_crop_offset * compptr->h_samp_factor; y_crop_blocks = y_crop_offset * compptr->v_samp_factor; for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; dst_blk_y += compptr->v_samp_factor) { dst_buffer = (*srcinfo->mem->access_virt_barray) ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y, (JDIMENSION) compptr->v_samp_factor, TRUE); for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; dst_blk_x += compptr->h_samp_factor) { if (x_crop_blocks + dst_blk_x < comp_width) { /* Block is within the mirrorable area. */ src_buffer = (*srcinfo->mem->access_virt_barray) ((j_common_ptr) srcinfo, src_coef_arrays[ci], comp_width - x_crop_blocks - dst_blk_x - (JDIMENSION) compptr->h_samp_factor, (JDIMENSION) compptr->h_samp_factor, FALSE); } else { src_buffer = (*srcinfo->mem->access_virt_barray) ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_x + x_crop_blocks, (JDIMENSION) compptr->h_samp_factor, FALSE); } for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) { dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x]; if (y_crop_blocks + dst_blk_y < comp_height) { if (x_crop_blocks + dst_blk_x < comp_width) { /* Block is within the mirrorable area. */ src_ptr = src_buffer[compptr->h_samp_factor - offset_x - 1] [comp_height - y_crop_blocks - dst_blk_y - offset_y - 1]; for (i = 0; i < DCTSIZE; i++) { for (j = 0; j < DCTSIZE; j++) { dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; j++; dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j]; } i++; for (j = 0; j < DCTSIZE; j++) { dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j]; j++; dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; } } } else { /* Right-edge blocks are mirrored in y only */ src_ptr = src_buffer[offset_x] [comp_height - y_crop_blocks - dst_blk_y - offset_y - 1]; for (i = 0; i < DCTSIZE; i++) { for (j = 0; j < DCTSIZE; j++) { dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; j++; dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j]; } } } } else { if (x_crop_blocks + dst_blk_x < comp_width) { /* Bottom-edge blocks are mirrored in x only */ src_ptr = src_buffer[compptr->h_samp_factor - offset_x - 1] [dst_blk_y + offset_y + y_crop_blocks]; for (i = 0; i < DCTSIZE; i++) { for (j = 0; j < DCTSIZE; j++) dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; i++; for (j = 0; j < DCTSIZE; j++) dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j]; } } else { /* At lower right corner, just transpose, no mirroring */ src_ptr = src_buffer[offset_x] [dst_blk_y + offset_y + y_crop_blocks]; for (i = 0; i < DCTSIZE; i++) for (j = 0; j < DCTSIZE; j++) dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; } } } } } } } } /* Parse an unsigned integer: subroutine for jtransform_parse_crop_spec. * Returns TRUE if valid integer found, FALSE if not. * *strptr is advanced over the digit string, and *result is set to its value. */ LOCAL(boolean) jt_read_integer (const char ** strptr, JDIMENSION * result) { const char * ptr = *strptr; JDIMENSION val = 0; for (; isdigit(*ptr); ptr++) { val = val * 10 + (JDIMENSION) (*ptr - '0'); } *result = val; if (ptr == *strptr) return FALSE; /* oops, no digits */ *strptr = ptr; return TRUE; } /* Parse a crop specification (written in X11 geometry style). * The routine returns TRUE if the spec string is valid, FALSE if not. * * The crop spec string should have the format * x{+-}{+-} * where width, height, xoffset, and yoffset are unsigned integers. * Each of the elements can be omitted to indicate a default value. * (A weakness of this style is that it is not possible to omit xoffset * while specifying yoffset, since they look alike.) * * This code is loosely based on XParseGeometry from the X11 distribution. */ GLOBAL(boolean) jtransform_parse_crop_spec (jpeg_transform_info *info, const char *spec) { info->crop = FALSE; info->crop_width_set = JCROP_UNSET; info->crop_height_set = JCROP_UNSET; info->crop_xoffset_set = JCROP_UNSET; info->crop_yoffset_set = JCROP_UNSET; if (isdigit(*spec)) { /* fetch width */ if (! jt_read_integer(&spec, &info->crop_width)) return FALSE; info->crop_width_set = JCROP_POS; } if (*spec == 'x' || *spec == 'X') { /* fetch height */ spec++; if (! jt_read_integer(&spec, &info->crop_height)) return FALSE; info->crop_height_set = JCROP_POS; } if (*spec == '+' || *spec == '-') { /* fetch xoffset */ info->crop_xoffset_set = (*spec == '-') ? JCROP_NEG : JCROP_POS; spec++; if (! jt_read_integer(&spec, &info->crop_xoffset)) return FALSE; } if (*spec == '+' || *spec == '-') { /* fetch yoffset */ info->crop_yoffset_set = (*spec == '-') ? JCROP_NEG : JCROP_POS; spec++; if (! jt_read_integer(&spec, &info->crop_yoffset)) return FALSE; } /* We had better have gotten to the end of the string. */ if (*spec != '\0') return FALSE; info->crop = TRUE; return TRUE; } /* Trim off any partial iMCUs on the indicated destination edge */ LOCAL(void) trim_right_edge (jpeg_transform_info *info, JDIMENSION full_width) { JDIMENSION MCU_cols; MCU_cols = info->output_width / info->iMCU_sample_width; if (MCU_cols > 0 && info->x_crop_offset + MCU_cols == full_width / info->iMCU_sample_width) info->output_width = MCU_cols * info->iMCU_sample_width; } LOCAL(void) trim_bottom_edge (jpeg_transform_info *info, JDIMENSION full_height) { JDIMENSION MCU_rows; MCU_rows = info->output_height / info->iMCU_sample_height; if (MCU_rows > 0 && info->y_crop_offset + MCU_rows == full_height / info->iMCU_sample_height) info->output_height = MCU_rows * info->iMCU_sample_height; } /* Request any required workspace. * * This routine figures out the size that the output image will be * (which implies that all the transform parameters must be set before * it is called). * * We allocate the workspace virtual arrays from the source decompression * object, so that all the arrays (both the original data and the workspace) * will be taken into account while making memory management decisions. * Hence, this routine must be called after jpeg_read_header (which reads * the image dimensions) and before jpeg_read_coefficients (which realizes * the source's virtual arrays). * * This function returns FALSE right away if -perfect is given * and transformation is not perfect. Otherwise returns TRUE. */ GLOBAL(boolean) jtransform_request_workspace (j_decompress_ptr srcinfo, jpeg_transform_info *info) { jvirt_barray_ptr *coef_arrays; boolean need_workspace, transpose_it; jpeg_component_info *compptr; JDIMENSION xoffset, yoffset; JDIMENSION width_in_iMCUs, height_in_iMCUs; JDIMENSION width_in_blocks, height_in_blocks; int ci, h_samp_factor, v_samp_factor; /* Determine number of components in output image */ if (info->force_grayscale && srcinfo->jpeg_color_space == JCS_YCbCr && srcinfo->num_components == 3) /* We'll only process the first component */ info->num_components = 1; else /* Process all the components */ info->num_components = srcinfo->num_components; /* Compute output image dimensions and related values. */ jpeg_core_output_dimensions(srcinfo); /* Return right away if -perfect is given and transformation is not perfect. */ if (info->perfect) { if (info->num_components == 1) { if (!jtransform_perfect_transform(srcinfo->output_width, srcinfo->output_height, srcinfo->min_DCT_h_scaled_size, srcinfo->min_DCT_v_scaled_size, info->transform)) return FALSE; } else { if (!jtransform_perfect_transform(srcinfo->output_width, srcinfo->output_height, srcinfo->max_h_samp_factor * srcinfo->min_DCT_h_scaled_size, srcinfo->max_v_samp_factor * srcinfo->min_DCT_v_scaled_size, info->transform)) return FALSE; } } /* If there is only one output component, force the iMCU size to be 1; * else use the source iMCU size. (This allows us to do the right thing * when reducing color to grayscale, and also provides a handy way of * cleaning up "funny" grayscale images whose sampling factors are not 1x1.) */ switch (info->transform) { case JXFORM_TRANSPOSE: case JXFORM_TRANSVERSE: case JXFORM_ROT_90: case JXFORM_ROT_270: info->output_width = srcinfo->output_height; info->output_height = srcinfo->output_width; if (info->num_components == 1) { info->iMCU_sample_width = srcinfo->min_DCT_v_scaled_size; info->iMCU_sample_height = srcinfo->min_DCT_h_scaled_size; } else { info->iMCU_sample_width = srcinfo->max_v_samp_factor * srcinfo->min_DCT_v_scaled_size; info->iMCU_sample_height = srcinfo->max_h_samp_factor * srcinfo->min_DCT_h_scaled_size; } break; default: info->output_width = srcinfo->output_width; info->output_height = srcinfo->output_height; if (info->num_components == 1) { info->iMCU_sample_width = srcinfo->min_DCT_h_scaled_size; info->iMCU_sample_height = srcinfo->min_DCT_v_scaled_size; } else { info->iMCU_sample_width = srcinfo->max_h_samp_factor * srcinfo->min_DCT_h_scaled_size; info->iMCU_sample_height = srcinfo->max_v_samp_factor * srcinfo->min_DCT_v_scaled_size; } break; } /* If cropping has been requested, compute the crop area's position and * dimensions, ensuring that its upper left corner falls at an iMCU boundary. */ if (info->crop) { /* Insert default values for unset crop parameters */ if (info->crop_xoffset_set == JCROP_UNSET) info->crop_xoffset = 0; /* default to +0 */ if (info->crop_yoffset_set == JCROP_UNSET) info->crop_yoffset = 0; /* default to +0 */ if (info->crop_xoffset >= info->output_width || info->crop_yoffset >= info->output_height) ERREXIT(srcinfo, JERR_BAD_CROP_SPEC); if (info->crop_width_set == JCROP_UNSET) info->crop_width = info->output_width - info->crop_xoffset; if (info->crop_height_set == JCROP_UNSET) info->crop_height = info->output_height - info->crop_yoffset; /* Ensure parameters are valid */ if (info->crop_width <= 0 || info->crop_width > info->output_width || info->crop_height <= 0 || info->crop_height > info->output_height || info->crop_xoffset > info->output_width - info->crop_width || info->crop_yoffset > info->output_height - info->crop_height) ERREXIT(srcinfo, JERR_BAD_CROP_SPEC); /* Convert negative crop offsets into regular offsets */ if (info->crop_xoffset_set == JCROP_NEG) xoffset = info->output_width - info->crop_width - info->crop_xoffset; else xoffset = info->crop_xoffset; if (info->crop_yoffset_set == JCROP_NEG) yoffset = info->output_height - info->crop_height - info->crop_yoffset; else yoffset = info->crop_yoffset; /* Now adjust so that upper left corner falls at an iMCU boundary */ info->output_width = info->crop_width + (xoffset % info->iMCU_sample_width); info->output_height = info->crop_height + (yoffset % info->iMCU_sample_height); /* Save x/y offsets measured in iMCUs */ info->x_crop_offset = xoffset / info->iMCU_sample_width; info->y_crop_offset = yoffset / info->iMCU_sample_height; } else { info->x_crop_offset = 0; info->y_crop_offset = 0; } /* Figure out whether we need workspace arrays, * and if so whether they are transposed relative to the source. */ need_workspace = FALSE; transpose_it = FALSE; switch (info->transform) { case JXFORM_NONE: if (info->x_crop_offset != 0 || info->y_crop_offset != 0) need_workspace = TRUE; /* No workspace needed if neither cropping nor transforming */ break; case JXFORM_FLIP_H: if (info->trim) trim_right_edge(info, srcinfo->output_width); if (info->y_crop_offset != 0) need_workspace = TRUE; /* do_flip_h_no_crop doesn't need a workspace array */ break; case JXFORM_FLIP_V: if (info->trim) trim_bottom_edge(info, srcinfo->output_height); /* Need workspace arrays having same dimensions as source image. */ need_workspace = TRUE; break; case JXFORM_TRANSPOSE: /* transpose does NOT have to trim anything */ /* Need workspace arrays having transposed dimensions. */ need_workspace = TRUE; transpose_it = TRUE; break; case JXFORM_TRANSVERSE: if (info->trim) { trim_right_edge(info, srcinfo->output_height); trim_bottom_edge(info, srcinfo->output_width); } /* Need workspace arrays having transposed dimensions. */ need_workspace = TRUE; transpose_it = TRUE; break; case JXFORM_ROT_90: if (info->trim) trim_right_edge(info, srcinfo->output_height); /* Need workspace arrays having transposed dimensions. */ need_workspace = TRUE; transpose_it = TRUE; break; case JXFORM_ROT_180: if (info->trim) { trim_right_edge(info, srcinfo->output_width); trim_bottom_edge(info, srcinfo->output_height); } /* Need workspace arrays having same dimensions as source image. */ need_workspace = TRUE; break; case JXFORM_ROT_270: if (info->trim) trim_bottom_edge(info, srcinfo->output_width); /* Need workspace arrays having transposed dimensions. */ need_workspace = TRUE; transpose_it = TRUE; break; } /* Allocate workspace if needed. * Note that we allocate arrays padded out to the next iMCU boundary, * so that transform routines need not worry about missing edge blocks. */ if (need_workspace) { coef_arrays = (jvirt_barray_ptr *) (*srcinfo->mem->alloc_small) ((j_common_ptr) srcinfo, JPOOL_IMAGE, SIZEOF(jvirt_barray_ptr) * info->num_components); width_in_iMCUs = (JDIMENSION) jdiv_round_up((long) info->output_width, (long) info->iMCU_sample_width); height_in_iMCUs = (JDIMENSION) jdiv_round_up((long) info->output_height, (long) info->iMCU_sample_height); for (ci = 0; ci < info->num_components; ci++) { compptr = srcinfo->comp_info + ci; if (info->num_components == 1) { /* we're going to force samp factors to 1x1 in this case */ h_samp_factor = v_samp_factor = 1; } else if (transpose_it) { h_samp_factor = compptr->v_samp_factor; v_samp_factor = compptr->h_samp_factor; } else { h_samp_factor = compptr->h_samp_factor; v_samp_factor = compptr->v_samp_factor; } width_in_blocks = width_in_iMCUs * h_samp_factor; height_in_blocks = height_in_iMCUs * v_samp_factor; coef_arrays[ci] = (*srcinfo->mem->request_virt_barray) ((j_common_ptr) srcinfo, JPOOL_IMAGE, FALSE, width_in_blocks, height_in_blocks, (JDIMENSION) v_samp_factor); } info->workspace_coef_arrays = coef_arrays; } else info->workspace_coef_arrays = NULL; return TRUE; } /* Transpose destination image parameters */ LOCAL(void) transpose_critical_parameters (j_compress_ptr dstinfo) { int tblno, i, j, ci, itemp; jpeg_component_info *compptr; JQUANT_TBL *qtblptr; JDIMENSION jtemp; UINT16 qtemp; /* Transpose image dimensions */ jtemp = dstinfo->image_width; dstinfo->image_width = dstinfo->image_height; dstinfo->image_height = jtemp; itemp = dstinfo->min_DCT_h_scaled_size; dstinfo->min_DCT_h_scaled_size = dstinfo->min_DCT_v_scaled_size; dstinfo->min_DCT_v_scaled_size = itemp; /* Transpose sampling factors */ for (ci = 0; ci < dstinfo->num_components; ci++) { compptr = dstinfo->comp_info + ci; itemp = compptr->h_samp_factor; compptr->h_samp_factor = compptr->v_samp_factor; compptr->v_samp_factor = itemp; } /* Transpose quantization tables */ for (tblno = 0; tblno < NUM_QUANT_TBLS; tblno++) { qtblptr = dstinfo->quant_tbl_ptrs[tblno]; if (qtblptr != NULL) { for (i = 0; i < DCTSIZE; i++) { for (j = 0; j < i; j++) { qtemp = qtblptr->quantval[i*DCTSIZE+j]; qtblptr->quantval[i*DCTSIZE+j] = qtblptr->quantval[j*DCTSIZE+i]; qtblptr->quantval[j*DCTSIZE+i] = qtemp; } } } } } /* Adjust Exif image parameters. * * We try to adjust the Tags ExifImageWidth and ExifImageHeight if possible. */ LOCAL(void) adjust_exif_parameters (JOCTET FAR * data, unsigned int length, JDIMENSION new_width, JDIMENSION new_height) { boolean is_motorola; /* Flag for byte order */ unsigned int number_of_tags, tagnum; unsigned int firstoffset, offset; JDIMENSION new_value; if (length < 12) return; /* Length of an IFD entry */ /* Discover byte order */ if (GETJOCTET(data[0]) == 0x49 && GETJOCTET(data[1]) == 0x49) is_motorola = FALSE; else if (GETJOCTET(data[0]) == 0x4D && GETJOCTET(data[1]) == 0x4D) is_motorola = TRUE; else return; /* Check Tag Mark */ if (is_motorola) { if (GETJOCTET(data[2]) != 0) return; if (GETJOCTET(data[3]) != 0x2A) return; } else { if (GETJOCTET(data[3]) != 0) return; if (GETJOCTET(data[2]) != 0x2A) return; } /* Get first IFD offset (offset to IFD0) */ if (is_motorola) { if (GETJOCTET(data[4]) != 0) return; if (GETJOCTET(data[5]) != 0) return; firstoffset = GETJOCTET(data[6]); firstoffset <<= 8; firstoffset += GETJOCTET(data[7]); } else { if (GETJOCTET(data[7]) != 0) return; if (GETJOCTET(data[6]) != 0) return; firstoffset = GETJOCTET(data[5]); firstoffset <<= 8; firstoffset += GETJOCTET(data[4]); } if (firstoffset > length - 2) return; /* check end of data segment */ /* Get the number of directory entries contained in this IFD */ if (is_motorola) { number_of_tags = GETJOCTET(data[firstoffset]); number_of_tags <<= 8; number_of_tags += GETJOCTET(data[firstoffset+1]); } else { number_of_tags = GETJOCTET(data[firstoffset+1]); number_of_tags <<= 8; number_of_tags += GETJOCTET(data[firstoffset]); } if (number_of_tags == 0) return; firstoffset += 2; /* Search for ExifSubIFD offset Tag in IFD0 */ for (;;) { if (firstoffset > length - 12) return; /* check end of data segment */ /* Get Tag number */ if (is_motorola) { tagnum = GETJOCTET(data[firstoffset]); tagnum <<= 8; tagnum += GETJOCTET(data[firstoffset+1]); } else { tagnum = GETJOCTET(data[firstoffset+1]); tagnum <<= 8; tagnum += GETJOCTET(data[firstoffset]); } if (tagnum == 0x8769) break; /* found ExifSubIFD offset Tag */ if (--number_of_tags == 0) return; firstoffset += 12; } /* Get the ExifSubIFD offset */ if (is_motorola) { if (GETJOCTET(data[firstoffset+8]) != 0) return; if (GETJOCTET(data[firstoffset+9]) != 0) return; offset = GETJOCTET(data[firstoffset+10]); offset <<= 8; offset += GETJOCTET(data[firstoffset+11]); } else { if (GETJOCTET(data[firstoffset+11]) != 0) return; if (GETJOCTET(data[firstoffset+10]) != 0) return; offset = GETJOCTET(data[firstoffset+9]); offset <<= 8; offset += GETJOCTET(data[firstoffset+8]); } if (offset > length - 2) return; /* check end of data segment */ /* Get the number of directory entries contained in this SubIFD */ if (is_motorola) { number_of_tags = GETJOCTET(data[offset]); number_of_tags <<= 8; number_of_tags += GETJOCTET(data[offset+1]); } else { number_of_tags = GETJOCTET(data[offset+1]); number_of_tags <<= 8; number_of_tags += GETJOCTET(data[offset]); } if (number_of_tags < 2) return; offset += 2; /* Search for ExifImageWidth and ExifImageHeight Tags in this SubIFD */ do { if (offset > length - 12) return; /* check end of data segment */ /* Get Tag number */ if (is_motorola) { tagnum = GETJOCTET(data[offset]); tagnum <<= 8; tagnum += GETJOCTET(data[offset+1]); } else { tagnum = GETJOCTET(data[offset+1]); tagnum <<= 8; tagnum += GETJOCTET(data[offset]); } if (tagnum == 0xA002 || tagnum == 0xA003) { if (tagnum == 0xA002) new_value = new_width; /* ExifImageWidth Tag */ else new_value = new_height; /* ExifImageHeight Tag */ if (is_motorola) { data[offset+2] = 0; /* Format = unsigned long (4 octets) */ data[offset+3] = 4; data[offset+4] = 0; /* Number Of Components = 1 */ data[offset+5] = 0; data[offset+6] = 0; data[offset+7] = 1; data[offset+8] = 0; data[offset+9] = 0; data[offset+10] = (JOCTET)((new_value >> 8) & 0xFF); data[offset+11] = (JOCTET)(new_value & 0xFF); } else { data[offset+2] = 4; /* Format = unsigned long (4 octets) */ data[offset+3] = 0; data[offset+4] = 1; /* Number Of Components = 1 */ data[offset+5] = 0; data[offset+6] = 0; data[offset+7] = 0; data[offset+8] = (JOCTET)(new_value & 0xFF); data[offset+9] = (JOCTET)((new_value >> 8) & 0xFF); data[offset+10] = 0; data[offset+11] = 0; } } offset += 12; } while (--number_of_tags); } /* Adjust output image parameters as needed. * * This must be called after jpeg_copy_critical_parameters() * and before jpeg_write_coefficients(). * * The return value is the set of virtual coefficient arrays to be written * (either the ones allocated by jtransform_request_workspace, or the * original source data arrays). The caller will need to pass this value * to jpeg_write_coefficients(). */ GLOBAL(jvirt_barray_ptr *) jtransform_adjust_parameters (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, jvirt_barray_ptr *src_coef_arrays, jpeg_transform_info *info) { /* If force-to-grayscale is requested, adjust destination parameters */ if (info->force_grayscale) { /* First, ensure we have YCbCr or grayscale data, and that the source's * Y channel is full resolution. (No reasonable person would make Y * be less than full resolution, so actually coping with that case * isn't worth extra code space. But we check it to avoid crashing.) */ if (((dstinfo->jpeg_color_space == JCS_YCbCr && dstinfo->num_components == 3) || (dstinfo->jpeg_color_space == JCS_GRAYSCALE && dstinfo->num_components == 1)) && srcinfo->comp_info[0].h_samp_factor == srcinfo->max_h_samp_factor && srcinfo->comp_info[0].v_samp_factor == srcinfo->max_v_samp_factor) { /* We use jpeg_set_colorspace to make sure subsidiary settings get fixed * properly. Among other things, it sets the target h_samp_factor & * v_samp_factor to 1, which typically won't match the source. * We have to preserve the source's quantization table number, however. */ int sv_quant_tbl_no = dstinfo->comp_info[0].quant_tbl_no; jpeg_set_colorspace(dstinfo, JCS_GRAYSCALE); dstinfo->comp_info[0].quant_tbl_no = sv_quant_tbl_no; } else { /* Sorry, can't do it */ ERREXIT(dstinfo, JERR_CONVERSION_NOTIMPL); } } else if (info->num_components == 1) { /* For a single-component source, we force the destination sampling factors * to 1x1, with or without force_grayscale. This is useful because some * decoders choke on grayscale images with other sampling factors. */ dstinfo->comp_info[0].h_samp_factor = 1; dstinfo->comp_info[0].v_samp_factor = 1; } /* Correct the destination's image dimensions as necessary * for rotate/flip, resize, and crop operations. */ dstinfo->jpeg_width = info->output_width; dstinfo->jpeg_height = info->output_height; /* Transpose destination image parameters */ switch (info->transform) { case JXFORM_TRANSPOSE: case JXFORM_TRANSVERSE: case JXFORM_ROT_90: case JXFORM_ROT_270: transpose_critical_parameters(dstinfo); break; default: break; } /* Adjust Exif properties */ if (srcinfo->marker_list != NULL && srcinfo->marker_list->marker == JPEG_APP0+1 && srcinfo->marker_list->data_length >= 6 && GETJOCTET(srcinfo->marker_list->data[0]) == 0x45 && GETJOCTET(srcinfo->marker_list->data[1]) == 0x78 && GETJOCTET(srcinfo->marker_list->data[2]) == 0x69 && GETJOCTET(srcinfo->marker_list->data[3]) == 0x66 && GETJOCTET(srcinfo->marker_list->data[4]) == 0 && GETJOCTET(srcinfo->marker_list->data[5]) == 0) { /* Suppress output of JFIF marker */ dstinfo->write_JFIF_header = FALSE; /* Adjust Exif image parameters */ if (dstinfo->jpeg_width != srcinfo->image_width || dstinfo->jpeg_height != srcinfo->image_height) /* Align data segment to start of TIFF structure for parsing */ adjust_exif_parameters(srcinfo->marker_list->data + 6, srcinfo->marker_list->data_length - 6, dstinfo->jpeg_width, dstinfo->jpeg_height); } /* Return the appropriate output data set */ if (info->workspace_coef_arrays != NULL) return info->workspace_coef_arrays; return src_coef_arrays; } /* Execute the actual transformation, if any. * * This must be called *after* jpeg_write_coefficients, because it depends * on jpeg_write_coefficients to have computed subsidiary values such as * the per-component width and height fields in the destination object. * * Note that some transformations will modify the source data arrays! */ GLOBAL(void) jtransform_execute_transform (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, jvirt_barray_ptr *src_coef_arrays, jpeg_transform_info *info) { jvirt_barray_ptr *dst_coef_arrays = info->workspace_coef_arrays; /* Note: conditions tested here should match those in switch statement * in jtransform_request_workspace() */ switch (info->transform) { case JXFORM_NONE: if (info->x_crop_offset != 0 || info->y_crop_offset != 0) do_crop(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset, src_coef_arrays, dst_coef_arrays); break; case JXFORM_FLIP_H: if (info->y_crop_offset != 0) do_flip_h(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset, src_coef_arrays, dst_coef_arrays); else do_flip_h_no_crop(srcinfo, dstinfo, info->x_crop_offset, src_coef_arrays); break; case JXFORM_FLIP_V: do_flip_v(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset, src_coef_arrays, dst_coef_arrays); break; case JXFORM_TRANSPOSE: do_transpose(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset, src_coef_arrays, dst_coef_arrays); break; case JXFORM_TRANSVERSE: do_transverse(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset, src_coef_arrays, dst_coef_arrays); break; case JXFORM_ROT_90: do_rot_90(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset, src_coef_arrays, dst_coef_arrays); break; case JXFORM_ROT_180: do_rot_180(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset, src_coef_arrays, dst_coef_arrays); break; case JXFORM_ROT_270: do_rot_270(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset, src_coef_arrays, dst_coef_arrays); break; } } /* jtransform_perfect_transform * * Determine whether lossless transformation is perfectly * possible for a specified image and transformation. * * Inputs: * image_width, image_height: source image dimensions. * MCU_width, MCU_height: pixel dimensions of MCU. * transform: transformation identifier. * Parameter sources from initialized jpeg_struct * (after reading source header): * image_width = cinfo.image_width * image_height = cinfo.image_height * MCU_width = cinfo.max_h_samp_factor * cinfo.block_size * MCU_height = cinfo.max_v_samp_factor * cinfo.block_size * Result: * TRUE = perfect transformation possible * FALSE = perfect transformation not possible * (may use custom action then) */ GLOBAL(boolean) jtransform_perfect_transform(JDIMENSION image_width, JDIMENSION image_height, int MCU_width, int MCU_height, JXFORM_CODE transform) { boolean result = TRUE; /* initialize TRUE */ switch (transform) { case JXFORM_FLIP_H: case JXFORM_ROT_270: if (image_width % (JDIMENSION) MCU_width) result = FALSE; break; case JXFORM_FLIP_V: case JXFORM_ROT_90: if (image_height % (JDIMENSION) MCU_height) result = FALSE; break; case JXFORM_TRANSVERSE: case JXFORM_ROT_180: if (image_width % (JDIMENSION) MCU_width) result = FALSE; if (image_height % (JDIMENSION) MCU_height) result = FALSE; break; default: break; } return result; } #endif /* TRANSFORMS_SUPPORTED */ /* Setup decompression object to save desired markers in memory. * This must be called before jpeg_read_header() to have the desired effect. */ GLOBAL(void) jcopy_markers_setup (j_decompress_ptr srcinfo, JCOPY_OPTION option) { #ifdef SAVE_MARKERS_SUPPORTED int m; /* Save comments except under NONE option */ if (option != JCOPYOPT_NONE) { jpeg_save_markers(srcinfo, JPEG_COM, 0xFFFF); } /* Save all types of APPn markers iff ALL option */ if (option == JCOPYOPT_ALL) { for (m = 0; m < 16; m++) jpeg_save_markers(srcinfo, JPEG_APP0 + m, 0xFFFF); } #endif /* SAVE_MARKERS_SUPPORTED */ } /* Copy markers saved in the given source object to the destination object. * This should be called just after jpeg_start_compress() or * jpeg_write_coefficients(). * Note that those routines will have written the SOI, and also the * JFIF APP0 or Adobe APP14 markers if selected. */ GLOBAL(void) jcopy_markers_execute (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, JCOPY_OPTION option) { jpeg_saved_marker_ptr marker; /* In the current implementation, we don't actually need to examine the * option flag here; we just copy everything that got saved. * But to avoid confusion, we do not output JFIF and Adobe APP14 markers * if the encoder library already wrote one. */ for (marker = srcinfo->marker_list; marker != NULL; marker = marker->next) { if (dstinfo->write_JFIF_header && marker->marker == JPEG_APP0 && marker->data_length >= 5 && GETJOCTET(marker->data[0]) == 0x4A && GETJOCTET(marker->data[1]) == 0x46 && GETJOCTET(marker->data[2]) == 0x49 && GETJOCTET(marker->data[3]) == 0x46 && GETJOCTET(marker->data[4]) == 0) continue; /* reject duplicate JFIF */ if (dstinfo->write_Adobe_marker && marker->marker == JPEG_APP0+14 && marker->data_length >= 5 && GETJOCTET(marker->data[0]) == 0x41 && GETJOCTET(marker->data[1]) == 0x64 && GETJOCTET(marker->data[2]) == 0x6F && GETJOCTET(marker->data[3]) == 0x62 && GETJOCTET(marker->data[4]) == 0x65) continue; /* reject duplicate Adobe */ #ifdef NEED_FAR_POINTERS /* We could use jpeg_write_marker if the data weren't FAR... */ { unsigned int i; jpeg_write_m_header(dstinfo, marker->marker, marker->data_length); for (i = 0; i < marker->data_length; i++) jpeg_write_m_byte(dstinfo, marker->data[i]); } #else jpeg_write_marker(dstinfo, marker->marker, marker->data, marker->data_length); #endif } } fbi-2.10/jpeg/80/jpeglib.h0000644000175000017500000013666412506525033013306 0ustar jmmjmm/* * jpeglib.h * * Copyright (C) 1991-1998, Thomas G. Lane. * Modified 2002-2010 by Guido Vollbeding. * This file is part of the Independent JPEG Group's software. * For conditions of distribution and use, see the accompanying README file. * * This file defines the application interface for the JPEG library. * Most applications using the library need only include this file, * and perhaps jerror.h if they want to know the exact error codes. */ #ifndef JPEGLIB_H #define JPEGLIB_H /* * First we include the configuration files that record how this * installation of the JPEG library is set up. jconfig.h can be * generated automatically for many systems. jmorecfg.h contains * manual configuration options that most people need not worry about. */ #ifndef JCONFIG_INCLUDED /* in case jinclude.h already did */ #include "jconfig.h" /* widely used configuration options */ #endif #include "jmorecfg.h" /* seldom changed options */ #ifdef __cplusplus #ifndef DONT_USE_EXTERN_C extern "C" { #endif #endif /* Version IDs for the JPEG library. * Might be useful for tests like "#if JPEG_LIB_VERSION >= 80". */ #define JPEG_LIB_VERSION 80 /* Compatibility version 8.0 */ #define JPEG_LIB_VERSION_MAJOR 8 #define JPEG_LIB_VERSION_MINOR 3 /* Various constants determining the sizes of things. * All of these are specified by the JPEG standard, so don't change them * if you want to be compatible. */ #define DCTSIZE 8 /* The basic DCT block is 8x8 samples */ #define DCTSIZE2 64 /* DCTSIZE squared; # of elements in a block */ #define NUM_QUANT_TBLS 4 /* Quantization tables are numbered 0..3 */ #define NUM_HUFF_TBLS 4 /* Huffman tables are numbered 0..3 */ #define NUM_ARITH_TBLS 16 /* Arith-coding tables are numbered 0..15 */ #define MAX_COMPS_IN_SCAN 4 /* JPEG limit on # of components in one scan */ #define MAX_SAMP_FACTOR 4 /* JPEG limit on sampling factors */ /* Unfortunately, some bozo at Adobe saw no reason to be bound by the standard; * the PostScript DCT filter can emit files with many more than 10 blocks/MCU. * If you happen to run across such a file, you can up D_MAX_BLOCKS_IN_MCU * to handle it. We even let you do this from the jconfig.h file. However, * we strongly discourage changing C_MAX_BLOCKS_IN_MCU; just because Adobe * sometimes emits noncompliant files doesn't mean you should too. */ #define C_MAX_BLOCKS_IN_MCU 10 /* compressor's limit on blocks per MCU */ #ifndef D_MAX_BLOCKS_IN_MCU #define D_MAX_BLOCKS_IN_MCU 10 /* decompressor's limit on blocks per MCU */ #endif /* Data structures for images (arrays of samples and of DCT coefficients). * On 80x86 machines, the image arrays are too big for near pointers, * but the pointer arrays can fit in near memory. */ typedef JSAMPLE FAR *JSAMPROW; /* ptr to one image row of pixel samples. */ typedef JSAMPROW *JSAMPARRAY; /* ptr to some rows (a 2-D sample array) */ typedef JSAMPARRAY *JSAMPIMAGE; /* a 3-D sample array: top index is color */ typedef JCOEF JBLOCK[DCTSIZE2]; /* one block of coefficients */ typedef JBLOCK FAR *JBLOCKROW; /* pointer to one row of coefficient blocks */ typedef JBLOCKROW *JBLOCKARRAY; /* a 2-D array of coefficient blocks */ typedef JBLOCKARRAY *JBLOCKIMAGE; /* a 3-D array of coefficient blocks */ typedef JCOEF FAR *JCOEFPTR; /* useful in a couple of places */ /* Types for JPEG compression parameters and working tables. */ /* DCT coefficient quantization tables. */ typedef struct { /* This array gives the coefficient quantizers in natural array order * (not the zigzag order in which they are stored in a JPEG DQT marker). * CAUTION: IJG versions prior to v6a kept this array in zigzag order. */ UINT16 quantval[DCTSIZE2]; /* quantization step for each coefficient */ /* This field is used only during compression. It's initialized FALSE when * the table is created, and set TRUE when it's been output to the file. * You could suppress output of a table by setting this to TRUE. * (See jpeg_suppress_tables for an example.) */ boolean sent_table; /* TRUE when table has been output */ } JQUANT_TBL; /* Huffman coding tables. */ typedef struct { /* These two fields directly represent the contents of a JPEG DHT marker */ UINT8 bits[17]; /* bits[k] = # of symbols with codes of */ /* length k bits; bits[0] is unused */ UINT8 huffval[256]; /* The symbols, in order of incr code length */ /* This field is used only during compression. It's initialized FALSE when * the table is created, and set TRUE when it's been output to the file. * You could suppress output of a table by setting this to TRUE. * (See jpeg_suppress_tables for an example.) */ boolean sent_table; /* TRUE when table has been output */ } JHUFF_TBL; /* Basic info about one component (color channel). */ typedef struct { /* These values are fixed over the whole image. */ /* For compression, they must be supplied by parameter setup; */ /* for decompression, they are read from the SOF marker. */ int component_id; /* identifier for this component (0..255) */ int component_index; /* its index in SOF or cinfo->comp_info[] */ int h_samp_factor; /* horizontal sampling factor (1..4) */ int v_samp_factor; /* vertical sampling factor (1..4) */ int quant_tbl_no; /* quantization table selector (0..3) */ /* These values may vary between scans. */ /* For compression, they must be supplied by parameter setup; */ /* for decompression, they are read from the SOS marker. */ /* The decompressor output side may not use these variables. */ int dc_tbl_no; /* DC entropy table selector (0..3) */ int ac_tbl_no; /* AC entropy table selector (0..3) */ /* Remaining fields should be treated as private by applications. */ /* These values are computed during compression or decompression startup: */ /* Component's size in DCT blocks. * Any dummy blocks added to complete an MCU are not counted; therefore * these values do not depend on whether a scan is interleaved or not. */ JDIMENSION width_in_blocks; JDIMENSION height_in_blocks; /* Size of a DCT block in samples, * reflecting any scaling we choose to apply during the DCT step. * Values from 1 to 16 are supported. * Note that different components may receive different DCT scalings. */ int DCT_h_scaled_size; int DCT_v_scaled_size; /* The downsampled dimensions are the component's actual, unpadded number * of samples at the main buffer (preprocessing/compression interface); * DCT scaling is included, so * downsampled_width = ceil(image_width * Hi/Hmax * DCT_h_scaled_size/DCTSIZE) * and similarly for height. */ JDIMENSION downsampled_width; /* actual width in samples */ JDIMENSION downsampled_height; /* actual height in samples */ /* This flag is used only for decompression. In cases where some of the * components will be ignored (eg grayscale output from YCbCr image), * we can skip most computations for the unused components. */ boolean component_needed; /* do we need the value of this component? */ /* These values are computed before starting a scan of the component. */ /* The decompressor output side may not use these variables. */ int MCU_width; /* number of blocks per MCU, horizontally */ int MCU_height; /* number of blocks per MCU, vertically */ int MCU_blocks; /* MCU_width * MCU_height */ int MCU_sample_width; /* MCU width in samples: MCU_width * DCT_h_scaled_size */ int last_col_width; /* # of non-dummy blocks across in last MCU */ int last_row_height; /* # of non-dummy blocks down in last MCU */ /* Saved quantization table for component; NULL if none yet saved. * See jdinput.c comments about the need for this information. * This field is currently used only for decompression. */ JQUANT_TBL * quant_table; /* Private per-component storage for DCT or IDCT subsystem. */ void * dct_table; } jpeg_component_info; /* The script for encoding a multiple-scan file is an array of these: */ typedef struct { int comps_in_scan; /* number of components encoded in this scan */ int component_index[MAX_COMPS_IN_SCAN]; /* their SOF/comp_info[] indexes */ int Ss, Se; /* progressive JPEG spectral selection parms */ int Ah, Al; /* progressive JPEG successive approx. parms */ } jpeg_scan_info; /* The decompressor can save APPn and COM markers in a list of these: */ typedef struct jpeg_marker_struct FAR * jpeg_saved_marker_ptr; struct jpeg_marker_struct { jpeg_saved_marker_ptr next; /* next in list, or NULL */ UINT8 marker; /* marker code: JPEG_COM, or JPEG_APP0+n */ unsigned int original_length; /* # bytes of data in the file */ unsigned int data_length; /* # bytes of data saved at data[] */ JOCTET FAR * data; /* the data contained in the marker */ /* the marker length word is not counted in data_length or original_length */ }; /* Known color spaces. */ typedef enum { JCS_UNKNOWN, /* error/unspecified */ JCS_GRAYSCALE, /* monochrome */ JCS_RGB, /* red/green/blue */ JCS_YCbCr, /* Y/Cb/Cr (also known as YUV) */ JCS_CMYK, /* C/M/Y/K */ JCS_YCCK /* Y/Cb/Cr/K */ } J_COLOR_SPACE; /* DCT/IDCT algorithm options. */ typedef enum { JDCT_ISLOW, /* slow but accurate integer algorithm */ JDCT_IFAST, /* faster, less accurate integer method */ JDCT_FLOAT /* floating-point: accurate, fast on fast HW */ } J_DCT_METHOD; #ifndef JDCT_DEFAULT /* may be overridden in jconfig.h */ #define JDCT_DEFAULT JDCT_ISLOW #endif #ifndef JDCT_FASTEST /* may be overridden in jconfig.h */ #define JDCT_FASTEST JDCT_IFAST #endif /* Dithering options for decompression. */ typedef enum { JDITHER_NONE, /* no dithering */ JDITHER_ORDERED, /* simple ordered dither */ JDITHER_FS /* Floyd-Steinberg error diffusion dither */ } J_DITHER_MODE; /* Common fields between JPEG compression and decompression master structs. */ #define jpeg_common_fields \ struct jpeg_error_mgr * err; /* Error handler module */\ struct jpeg_memory_mgr * mem; /* Memory manager module */\ struct jpeg_progress_mgr * progress; /* Progress monitor, or NULL if none */\ void * client_data; /* Available for use by application */\ boolean is_decompressor; /* So common code can tell which is which */\ int global_state /* For checking call sequence validity */ /* Routines that are to be used by both halves of the library are declared * to receive a pointer to this structure. There are no actual instances of * jpeg_common_struct, only of jpeg_compress_struct and jpeg_decompress_struct. */ struct jpeg_common_struct { jpeg_common_fields; /* Fields common to both master struct types */ /* Additional fields follow in an actual jpeg_compress_struct or * jpeg_decompress_struct. All three structs must agree on these * initial fields! (This would be a lot cleaner in C++.) */ }; typedef struct jpeg_common_struct * j_common_ptr; typedef struct jpeg_compress_struct * j_compress_ptr; typedef struct jpeg_decompress_struct * j_decompress_ptr; /* Master record for a compression instance */ struct jpeg_compress_struct { jpeg_common_fields; /* Fields shared with jpeg_decompress_struct */ /* Destination for compressed data */ struct jpeg_destination_mgr * dest; /* Description of source image --- these fields must be filled in by * outer application before starting compression. in_color_space must * be correct before you can even call jpeg_set_defaults(). */ JDIMENSION image_width; /* input image width */ JDIMENSION image_height; /* input image height */ int input_components; /* # of color components in input image */ J_COLOR_SPACE in_color_space; /* colorspace of input image */ double input_gamma; /* image gamma of input image */ /* Compression parameters --- these fields must be set before calling * jpeg_start_compress(). We recommend calling jpeg_set_defaults() to * initialize everything to reasonable defaults, then changing anything * the application specifically wants to change. That way you won't get * burnt when new parameters are added. Also note that there are several * helper routines to simplify changing parameters. */ unsigned int scale_num, scale_denom; /* fraction by which to scale image */ JDIMENSION jpeg_width; /* scaled JPEG image width */ JDIMENSION jpeg_height; /* scaled JPEG image height */ /* Dimensions of actual JPEG image that will be written to file, * derived from input dimensions by scaling factors above. * These fields are computed by jpeg_start_compress(). * You can also use jpeg_calc_jpeg_dimensions() to determine these values * in advance of calling jpeg_start_compress(). */ int data_precision; /* bits of precision in image data */ int num_components; /* # of color components in JPEG image */ J_COLOR_SPACE jpeg_color_space; /* colorspace of JPEG image */ jpeg_component_info * comp_info; /* comp_info[i] describes component that appears i'th in SOF */ JQUANT_TBL * quant_tbl_ptrs[NUM_QUANT_TBLS]; int q_scale_factor[NUM_QUANT_TBLS]; /* ptrs to coefficient quantization tables, or NULL if not defined, * and corresponding scale factors (percentage, initialized 100). */ JHUFF_TBL * dc_huff_tbl_ptrs[NUM_HUFF_TBLS]; JHUFF_TBL * ac_huff_tbl_ptrs[NUM_HUFF_TBLS]; /* ptrs to Huffman coding tables, or NULL if not defined */ UINT8 arith_dc_L[NUM_ARITH_TBLS]; /* L values for DC arith-coding tables */ UINT8 arith_dc_U[NUM_ARITH_TBLS]; /* U values for DC arith-coding tables */ UINT8 arith_ac_K[NUM_ARITH_TBLS]; /* Kx values for AC arith-coding tables */ int num_scans; /* # of entries in scan_info array */ const jpeg_scan_info * scan_info; /* script for multi-scan file, or NULL */ /* The default value of scan_info is NULL, which causes a single-scan * sequential JPEG file to be emitted. To create a multi-scan file, * set num_scans and scan_info to point to an array of scan definitions. */ boolean raw_data_in; /* TRUE=caller supplies downsampled data */ boolean arith_code; /* TRUE=arithmetic coding, FALSE=Huffman */ boolean optimize_coding; /* TRUE=optimize entropy encoding parms */ boolean CCIR601_sampling; /* TRUE=first samples are cosited */ boolean do_fancy_downsampling; /* TRUE=apply fancy downsampling */ int smoothing_factor; /* 1..100, or 0 for no input smoothing */ J_DCT_METHOD dct_method; /* DCT algorithm selector */ /* The restart interval can be specified in absolute MCUs by setting * restart_interval, or in MCU rows by setting restart_in_rows * (in which case the correct restart_interval will be figured * for each scan). */ unsigned int restart_interval; /* MCUs per restart, or 0 for no restart */ int restart_in_rows; /* if > 0, MCU rows per restart interval */ /* Parameters controlling emission of special markers. */ boolean write_JFIF_header; /* should a JFIF marker be written? */ UINT8 JFIF_major_version; /* What to write for the JFIF version number */ UINT8 JFIF_minor_version; /* These three values are not used by the JPEG code, merely copied */ /* into the JFIF APP0 marker. density_unit can be 0 for unknown, */ /* 1 for dots/inch, or 2 for dots/cm. Note that the pixel aspect */ /* ratio is defined by X_density/Y_density even when density_unit=0. */ UINT8 density_unit; /* JFIF code for pixel size units */ UINT16 X_density; /* Horizontal pixel density */ UINT16 Y_density; /* Vertical pixel density */ boolean write_Adobe_marker; /* should an Adobe marker be written? */ /* State variable: index of next scanline to be written to * jpeg_write_scanlines(). Application may use this to control its * processing loop, e.g., "while (next_scanline < image_height)". */ JDIMENSION next_scanline; /* 0 .. image_height-1 */ /* Remaining fields are known throughout compressor, but generally * should not be touched by a surrounding application. */ /* * These fields are computed during compression startup */ boolean progressive_mode; /* TRUE if scan script uses progressive mode */ int max_h_samp_factor; /* largest h_samp_factor */ int max_v_samp_factor; /* largest v_samp_factor */ int min_DCT_h_scaled_size; /* smallest DCT_h_scaled_size of any component */ int min_DCT_v_scaled_size; /* smallest DCT_v_scaled_size of any component */ JDIMENSION total_iMCU_rows; /* # of iMCU rows to be input to coef ctlr */ /* The coefficient controller receives data in units of MCU rows as defined * for fully interleaved scans (whether the JPEG file is interleaved or not). * There are v_samp_factor * DCTSIZE sample rows of each component in an * "iMCU" (interleaved MCU) row. */ /* * These fields are valid during any one scan. * They describe the components and MCUs actually appearing in the scan. */ int comps_in_scan; /* # of JPEG components in this scan */ jpeg_component_info * cur_comp_info[MAX_COMPS_IN_SCAN]; /* *cur_comp_info[i] describes component that appears i'th in SOS */ JDIMENSION MCUs_per_row; /* # of MCUs across the image */ JDIMENSION MCU_rows_in_scan; /* # of MCU rows in the image */ int blocks_in_MCU; /* # of DCT blocks per MCU */ int MCU_membership[C_MAX_BLOCKS_IN_MCU]; /* MCU_membership[i] is index in cur_comp_info of component owning */ /* i'th block in an MCU */ int Ss, Se, Ah, Al; /* progressive JPEG parameters for scan */ int block_size; /* the basic DCT block size: 1..16 */ const int * natural_order; /* natural-order position array */ int lim_Se; /* min( Se, DCTSIZE2-1 ) */ /* * Links to compression subobjects (methods and private variables of modules) */ struct jpeg_comp_master * master; struct jpeg_c_main_controller * main; struct jpeg_c_prep_controller * prep; struct jpeg_c_coef_controller * coef; struct jpeg_marker_writer * marker; struct jpeg_color_converter * cconvert; struct jpeg_downsampler * downsample; struct jpeg_forward_dct * fdct; struct jpeg_entropy_encoder * entropy; jpeg_scan_info * script_space; /* workspace for jpeg_simple_progression */ int script_space_size; }; /* Master record for a decompression instance */ struct jpeg_decompress_struct { jpeg_common_fields; /* Fields shared with jpeg_compress_struct */ /* Source of compressed data */ struct jpeg_source_mgr * src; /* Basic description of image --- filled in by jpeg_read_header(). */ /* Application may inspect these values to decide how to process image. */ JDIMENSION image_width; /* nominal image width (from SOF marker) */ JDIMENSION image_height; /* nominal image height */ int num_components; /* # of color components in JPEG image */ J_COLOR_SPACE jpeg_color_space; /* colorspace of JPEG image */ /* Decompression processing parameters --- these fields must be set before * calling jpeg_start_decompress(). Note that jpeg_read_header() initializes * them to default values. */ J_COLOR_SPACE out_color_space; /* colorspace for output */ unsigned int scale_num, scale_denom; /* fraction by which to scale image */ double output_gamma; /* image gamma wanted in output */ boolean buffered_image; /* TRUE=multiple output passes */ boolean raw_data_out; /* TRUE=downsampled data wanted */ J_DCT_METHOD dct_method; /* IDCT algorithm selector */ boolean do_fancy_upsampling; /* TRUE=apply fancy upsampling */ boolean do_block_smoothing; /* TRUE=apply interblock smoothing */ boolean quantize_colors; /* TRUE=colormapped output wanted */ /* the following are ignored if not quantize_colors: */ J_DITHER_MODE dither_mode; /* type of color dithering to use */ boolean two_pass_quantize; /* TRUE=use two-pass color quantization */ int desired_number_of_colors; /* max # colors to use in created colormap */ /* these are significant only in buffered-image mode: */ boolean enable_1pass_quant; /* enable future use of 1-pass quantizer */ boolean enable_external_quant;/* enable future use of external colormap */ boolean enable_2pass_quant; /* enable future use of 2-pass quantizer */ /* Description of actual output image that will be returned to application. * These fields are computed by jpeg_start_decompress(). * You can also use jpeg_calc_output_dimensions() to determine these values * in advance of calling jpeg_start_decompress(). */ JDIMENSION output_width; /* scaled image width */ JDIMENSION output_height; /* scaled image height */ int out_color_components; /* # of color components in out_color_space */ int output_components; /* # of color components returned */ /* output_components is 1 (a colormap index) when quantizing colors; * otherwise it equals out_color_components. */ int rec_outbuf_height; /* min recommended height of scanline buffer */ /* If the buffer passed to jpeg_read_scanlines() is less than this many rows * high, space and time will be wasted due to unnecessary data copying. * Usually rec_outbuf_height will be 1 or 2, at most 4. */ /* When quantizing colors, the output colormap is described by these fields. * The application can supply a colormap by setting colormap non-NULL before * calling jpeg_start_decompress; otherwise a colormap is created during * jpeg_start_decompress or jpeg_start_output. * The map has out_color_components rows and actual_number_of_colors columns. */ int actual_number_of_colors; /* number of entries in use */ JSAMPARRAY colormap; /* The color map as a 2-D pixel array */ /* State variables: these variables indicate the progress of decompression. * The application may examine these but must not modify them. */ /* Row index of next scanline to be read from jpeg_read_scanlines(). * Application may use this to control its processing loop, e.g., * "while (output_scanline < output_height)". */ JDIMENSION output_scanline; /* 0 .. output_height-1 */ /* Current input scan number and number of iMCU rows completed in scan. * These indicate the progress of the decompressor input side. */ int input_scan_number; /* Number of SOS markers seen so far */ JDIMENSION input_iMCU_row; /* Number of iMCU rows completed */ /* The "output scan number" is the notional scan being displayed by the * output side. The decompressor will not allow output scan/row number * to get ahead of input scan/row, but it can fall arbitrarily far behind. */ int output_scan_number; /* Nominal scan number being displayed */ JDIMENSION output_iMCU_row; /* Number of iMCU rows read */ /* Current progression status. coef_bits[c][i] indicates the precision * with which component c's DCT coefficient i (in zigzag order) is known. * It is -1 when no data has yet been received, otherwise it is the point * transform (shift) value for the most recent scan of the coefficient * (thus, 0 at completion of the progression). * This pointer is NULL when reading a non-progressive file. */ int (*coef_bits)[DCTSIZE2]; /* -1 or current Al value for each coef */ /* Internal JPEG parameters --- the application usually need not look at * these fields. Note that the decompressor output side may not use * any parameters that can change between scans. */ /* Quantization and Huffman tables are carried forward across input * datastreams when processing abbreviated JPEG datastreams. */ JQUANT_TBL * quant_tbl_ptrs[NUM_QUANT_TBLS]; /* ptrs to coefficient quantization tables, or NULL if not defined */ JHUFF_TBL * dc_huff_tbl_ptrs[NUM_HUFF_TBLS]; JHUFF_TBL * ac_huff_tbl_ptrs[NUM_HUFF_TBLS]; /* ptrs to Huffman coding tables, or NULL if not defined */ /* These parameters are never carried across datastreams, since they * are given in SOF/SOS markers or defined to be reset by SOI. */ int data_precision; /* bits of precision in image data */ jpeg_component_info * comp_info; /* comp_info[i] describes component that appears i'th in SOF */ boolean is_baseline; /* TRUE if Baseline SOF0 encountered */ boolean progressive_mode; /* TRUE if SOFn specifies progressive mode */ boolean arith_code; /* TRUE=arithmetic coding, FALSE=Huffman */ UINT8 arith_dc_L[NUM_ARITH_TBLS]; /* L values for DC arith-coding tables */ UINT8 arith_dc_U[NUM_ARITH_TBLS]; /* U values for DC arith-coding tables */ UINT8 arith_ac_K[NUM_ARITH_TBLS]; /* Kx values for AC arith-coding tables */ unsigned int restart_interval; /* MCUs per restart interval, or 0 for no restart */ /* These fields record data obtained from optional markers recognized by * the JPEG library. */ boolean saw_JFIF_marker; /* TRUE iff a JFIF APP0 marker was found */ /* Data copied from JFIF marker; only valid if saw_JFIF_marker is TRUE: */ UINT8 JFIF_major_version; /* JFIF version number */ UINT8 JFIF_minor_version; UINT8 density_unit; /* JFIF code for pixel size units */ UINT16 X_density; /* Horizontal pixel density */ UINT16 Y_density; /* Vertical pixel density */ boolean saw_Adobe_marker; /* TRUE iff an Adobe APP14 marker was found */ UINT8 Adobe_transform; /* Color transform code from Adobe marker */ boolean CCIR601_sampling; /* TRUE=first samples are cosited */ /* Aside from the specific data retained from APPn markers known to the * library, the uninterpreted contents of any or all APPn and COM markers * can be saved in a list for examination by the application. */ jpeg_saved_marker_ptr marker_list; /* Head of list of saved markers */ /* Remaining fields are known throughout decompressor, but generally * should not be touched by a surrounding application. */ /* * These fields are computed during decompression startup */ int max_h_samp_factor; /* largest h_samp_factor */ int max_v_samp_factor; /* largest v_samp_factor */ int min_DCT_h_scaled_size; /* smallest DCT_h_scaled_size of any component */ int min_DCT_v_scaled_size; /* smallest DCT_v_scaled_size of any component */ JDIMENSION total_iMCU_rows; /* # of iMCU rows in image */ /* The coefficient controller's input and output progress is measured in * units of "iMCU" (interleaved MCU) rows. These are the same as MCU rows * in fully interleaved JPEG scans, but are used whether the scan is * interleaved or not. We define an iMCU row as v_samp_factor DCT block * rows of each component. Therefore, the IDCT output contains * v_samp_factor*DCT_v_scaled_size sample rows of a component per iMCU row. */ JSAMPLE * sample_range_limit; /* table for fast range-limiting */ /* * These fields are valid during any one scan. * They describe the components and MCUs actually appearing in the scan. * Note that the decompressor output side must not use these fields. */ int comps_in_scan; /* # of JPEG components in this scan */ jpeg_component_info * cur_comp_info[MAX_COMPS_IN_SCAN]; /* *cur_comp_info[i] describes component that appears i'th in SOS */ JDIMENSION MCUs_per_row; /* # of MCUs across the image */ JDIMENSION MCU_rows_in_scan; /* # of MCU rows in the image */ int blocks_in_MCU; /* # of DCT blocks per MCU */ int MCU_membership[D_MAX_BLOCKS_IN_MCU]; /* MCU_membership[i] is index in cur_comp_info of component owning */ /* i'th block in an MCU */ int Ss, Se, Ah, Al; /* progressive JPEG parameters for scan */ /* These fields are derived from Se of first SOS marker. */ int block_size; /* the basic DCT block size: 1..16 */ const int * natural_order; /* natural-order position array for entropy decode */ int lim_Se; /* min( Se, DCTSIZE2-1 ) for entropy decode */ /* This field is shared between entropy decoder and marker parser. * It is either zero or the code of a JPEG marker that has been * read from the data source, but has not yet been processed. */ int unread_marker; /* * Links to decompression subobjects (methods, private variables of modules) */ struct jpeg_decomp_master * master; struct jpeg_d_main_controller * main; struct jpeg_d_coef_controller * coef; struct jpeg_d_post_controller * post; struct jpeg_input_controller * inputctl; struct jpeg_marker_reader * marker; struct jpeg_entropy_decoder * entropy; struct jpeg_inverse_dct * idct; struct jpeg_upsampler * upsample; struct jpeg_color_deconverter * cconvert; struct jpeg_color_quantizer * cquantize; }; /* "Object" declarations for JPEG modules that may be supplied or called * directly by the surrounding application. * As with all objects in the JPEG library, these structs only define the * publicly visible methods and state variables of a module. Additional * private fields may exist after the public ones. */ /* Error handler object */ struct jpeg_error_mgr { /* Error exit handler: does not return to caller */ JMETHOD(void, error_exit, (j_common_ptr cinfo)); /* Conditionally emit a trace or warning message */ JMETHOD(void, emit_message, (j_common_ptr cinfo, int msg_level)); /* Routine that actually outputs a trace or error message */ JMETHOD(void, output_message, (j_common_ptr cinfo)); /* Format a message string for the most recent JPEG error or message */ JMETHOD(void, format_message, (j_common_ptr cinfo, char * buffer)); #define JMSG_LENGTH_MAX 200 /* recommended size of format_message buffer */ /* Reset error state variables at start of a new image */ JMETHOD(void, reset_error_mgr, (j_common_ptr cinfo)); /* The message ID code and any parameters are saved here. * A message can have one string parameter or up to 8 int parameters. */ int msg_code; #define JMSG_STR_PARM_MAX 80 union { int i[8]; char s[JMSG_STR_PARM_MAX]; } msg_parm; /* Standard state variables for error facility */ int trace_level; /* max msg_level that will be displayed */ /* For recoverable corrupt-data errors, we emit a warning message, * but keep going unless emit_message chooses to abort. emit_message * should count warnings in num_warnings. The surrounding application * can check for bad data by seeing if num_warnings is nonzero at the * end of processing. */ long num_warnings; /* number of corrupt-data warnings */ /* These fields point to the table(s) of error message strings. * An application can change the table pointer to switch to a different * message list (typically, to change the language in which errors are * reported). Some applications may wish to add additional error codes * that will be handled by the JPEG library error mechanism; the second * table pointer is used for this purpose. * * First table includes all errors generated by JPEG library itself. * Error code 0 is reserved for a "no such error string" message. */ const char * const * jpeg_message_table; /* Library errors */ int last_jpeg_message; /* Table contains strings 0..last_jpeg_message */ /* Second table can be added by application (see cjpeg/djpeg for example). * It contains strings numbered first_addon_message..last_addon_message. */ const char * const * addon_message_table; /* Non-library errors */ int first_addon_message; /* code for first string in addon table */ int last_addon_message; /* code for last string in addon table */ }; /* Progress monitor object */ struct jpeg_progress_mgr { JMETHOD(void, progress_monitor, (j_common_ptr cinfo)); long pass_counter; /* work units completed in this pass */ long pass_limit; /* total number of work units in this pass */ int completed_passes; /* passes completed so far */ int total_passes; /* total number of passes expected */ }; /* Data destination object for compression */ struct jpeg_destination_mgr { JOCTET * next_output_byte; /* => next byte to write in buffer */ size_t free_in_buffer; /* # of byte spaces remaining in buffer */ JMETHOD(void, init_destination, (j_compress_ptr cinfo)); JMETHOD(boolean, empty_output_buffer, (j_compress_ptr cinfo)); JMETHOD(void, term_destination, (j_compress_ptr cinfo)); }; /* Data source object for decompression */ struct jpeg_source_mgr { const JOCTET * next_input_byte; /* => next byte to read from buffer */ size_t bytes_in_buffer; /* # of bytes remaining in buffer */ JMETHOD(void, init_source, (j_decompress_ptr cinfo)); JMETHOD(boolean, fill_input_buffer, (j_decompress_ptr cinfo)); JMETHOD(void, skip_input_data, (j_decompress_ptr cinfo, long num_bytes)); JMETHOD(boolean, resync_to_restart, (j_decompress_ptr cinfo, int desired)); JMETHOD(void, term_source, (j_decompress_ptr cinfo)); }; /* Memory manager object. * Allocates "small" objects (a few K total), "large" objects (tens of K), * and "really big" objects (virtual arrays with backing store if needed). * The memory manager does not allow individual objects to be freed; rather, * each created object is assigned to a pool, and whole pools can be freed * at once. This is faster and more convenient than remembering exactly what * to free, especially where malloc()/free() are not too speedy. * NB: alloc routines never return NULL. They exit to error_exit if not * successful. */ #define JPOOL_PERMANENT 0 /* lasts until master record is destroyed */ #define JPOOL_IMAGE 1 /* lasts until done with image/datastream */ #define JPOOL_NUMPOOLS 2 typedef struct jvirt_sarray_control * jvirt_sarray_ptr; typedef struct jvirt_barray_control * jvirt_barray_ptr; struct jpeg_memory_mgr { /* Method pointers */ JMETHOD(void *, alloc_small, (j_common_ptr cinfo, int pool_id, size_t sizeofobject)); JMETHOD(void FAR *, alloc_large, (j_common_ptr cinfo, int pool_id, size_t sizeofobject)); JMETHOD(JSAMPARRAY, alloc_sarray, (j_common_ptr cinfo, int pool_id, JDIMENSION samplesperrow, JDIMENSION numrows)); JMETHOD(JBLOCKARRAY, alloc_barray, (j_common_ptr cinfo, int pool_id, JDIMENSION blocksperrow, JDIMENSION numrows)); JMETHOD(jvirt_sarray_ptr, request_virt_sarray, (j_common_ptr cinfo, int pool_id, boolean pre_zero, JDIMENSION samplesperrow, JDIMENSION numrows, JDIMENSION maxaccess)); JMETHOD(jvirt_barray_ptr, request_virt_barray, (j_common_ptr cinfo, int pool_id, boolean pre_zero, JDIMENSION blocksperrow, JDIMENSION numrows, JDIMENSION maxaccess)); JMETHOD(void, realize_virt_arrays, (j_common_ptr cinfo)); JMETHOD(JSAMPARRAY, access_virt_sarray, (j_common_ptr cinfo, jvirt_sarray_ptr ptr, JDIMENSION start_row, JDIMENSION num_rows, boolean writable)); JMETHOD(JBLOCKARRAY, access_virt_barray, (j_common_ptr cinfo, jvirt_barray_ptr ptr, JDIMENSION start_row, JDIMENSION num_rows, boolean writable)); JMETHOD(void, free_pool, (j_common_ptr cinfo, int pool_id)); JMETHOD(void, self_destruct, (j_common_ptr cinfo)); /* Limit on memory allocation for this JPEG object. (Note that this is * merely advisory, not a guaranteed maximum; it only affects the space * used for virtual-array buffers.) May be changed by outer application * after creating the JPEG object. */ long max_memory_to_use; /* Maximum allocation request accepted by alloc_large. */ long max_alloc_chunk; }; /* Routine signature for application-supplied marker processing methods. * Need not pass marker code since it is stored in cinfo->unread_marker. */ typedef JMETHOD(boolean, jpeg_marker_parser_method, (j_decompress_ptr cinfo)); /* Declarations for routines called by application. * The JPP macro hides prototype parameters from compilers that can't cope. * Note JPP requires double parentheses. */ #ifdef HAVE_PROTOTYPES #define JPP(arglist) arglist #else #define JPP(arglist) () #endif /* Short forms of external names for systems with brain-damaged linkers. * We shorten external names to be unique in the first six letters, which * is good enough for all known systems. * (If your compiler itself needs names to be unique in less than 15 * characters, you are out of luck. Get a better compiler.) */ #ifdef NEED_SHORT_EXTERNAL_NAMES #define jpeg_std_error jStdError #define jpeg_CreateCompress jCreaCompress #define jpeg_CreateDecompress jCreaDecompress #define jpeg_destroy_compress jDestCompress #define jpeg_destroy_decompress jDestDecompress #define jpeg_stdio_dest jStdDest #define jpeg_stdio_src jStdSrc #define jpeg_mem_dest jMemDest #define jpeg_mem_src jMemSrc #define jpeg_set_defaults jSetDefaults #define jpeg_set_colorspace jSetColorspace #define jpeg_default_colorspace jDefColorspace #define jpeg_set_quality jSetQuality #define jpeg_set_linear_quality jSetLQuality #define jpeg_default_qtables jDefQTables #define jpeg_add_quant_table jAddQuantTable #define jpeg_quality_scaling jQualityScaling #define jpeg_simple_progression jSimProgress #define jpeg_suppress_tables jSuppressTables #define jpeg_alloc_quant_table jAlcQTable #define jpeg_alloc_huff_table jAlcHTable #define jpeg_start_compress jStrtCompress #define jpeg_write_scanlines jWrtScanlines #define jpeg_finish_compress jFinCompress #define jpeg_calc_jpeg_dimensions jCjpegDimensions #define jpeg_write_raw_data jWrtRawData #define jpeg_write_marker jWrtMarker #define jpeg_write_m_header jWrtMHeader #define jpeg_write_m_byte jWrtMByte #define jpeg_write_tables jWrtTables #define jpeg_read_header jReadHeader #define jpeg_start_decompress jStrtDecompress #define jpeg_read_scanlines jReadScanlines #define jpeg_finish_decompress jFinDecompress #define jpeg_read_raw_data jReadRawData #define jpeg_has_multiple_scans jHasMultScn #define jpeg_start_output jStrtOutput #define jpeg_finish_output jFinOutput #define jpeg_input_complete jInComplete #define jpeg_new_colormap jNewCMap #define jpeg_consume_input jConsumeInput #define jpeg_core_output_dimensions jCoreDimensions #define jpeg_calc_output_dimensions jCalcDimensions #define jpeg_save_markers jSaveMarkers #define jpeg_set_marker_processor jSetMarker #define jpeg_read_coefficients jReadCoefs #define jpeg_write_coefficients jWrtCoefs #define jpeg_copy_critical_parameters jCopyCrit #define jpeg_abort_compress jAbrtCompress #define jpeg_abort_decompress jAbrtDecompress #define jpeg_abort jAbort #define jpeg_destroy jDestroy #define jpeg_resync_to_restart jResyncRestart #endif /* NEED_SHORT_EXTERNAL_NAMES */ /* Default error-management setup */ EXTERN(struct jpeg_error_mgr *) jpeg_std_error JPP((struct jpeg_error_mgr * err)); /* Initialization of JPEG compression objects. * jpeg_create_compress() and jpeg_create_decompress() are the exported * names that applications should call. These expand to calls on * jpeg_CreateCompress and jpeg_CreateDecompress with additional information * passed for version mismatch checking. * NB: you must set up the error-manager BEFORE calling jpeg_create_xxx. */ #define jpeg_create_compress(cinfo) \ jpeg_CreateCompress((cinfo), JPEG_LIB_VERSION, \ (size_t) sizeof(struct jpeg_compress_struct)) #define jpeg_create_decompress(cinfo) \ jpeg_CreateDecompress((cinfo), JPEG_LIB_VERSION, \ (size_t) sizeof(struct jpeg_decompress_struct)) EXTERN(void) jpeg_CreateCompress JPP((j_compress_ptr cinfo, int version, size_t structsize)); EXTERN(void) jpeg_CreateDecompress JPP((j_decompress_ptr cinfo, int version, size_t structsize)); /* Destruction of JPEG compression objects */ EXTERN(void) jpeg_destroy_compress JPP((j_compress_ptr cinfo)); EXTERN(void) jpeg_destroy_decompress JPP((j_decompress_ptr cinfo)); /* Standard data source and destination managers: stdio streams. */ /* Caller is responsible for opening the file before and closing after. */ EXTERN(void) jpeg_stdio_dest JPP((j_compress_ptr cinfo, FILE * outfile)); EXTERN(void) jpeg_stdio_src JPP((j_decompress_ptr cinfo, FILE * infile)); /* Data source and destination managers: memory buffers. */ EXTERN(void) jpeg_mem_dest JPP((j_compress_ptr cinfo, unsigned char ** outbuffer, unsigned long * outsize)); EXTERN(void) jpeg_mem_src JPP((j_decompress_ptr cinfo, unsigned char * inbuffer, unsigned long insize)); /* Default parameter setup for compression */ EXTERN(void) jpeg_set_defaults JPP((j_compress_ptr cinfo)); /* Compression parameter setup aids */ EXTERN(void) jpeg_set_colorspace JPP((j_compress_ptr cinfo, J_COLOR_SPACE colorspace)); EXTERN(void) jpeg_default_colorspace JPP((j_compress_ptr cinfo)); EXTERN(void) jpeg_set_quality JPP((j_compress_ptr cinfo, int quality, boolean force_baseline)); EXTERN(void) jpeg_set_linear_quality JPP((j_compress_ptr cinfo, int scale_factor, boolean force_baseline)); EXTERN(void) jpeg_default_qtables JPP((j_compress_ptr cinfo, boolean force_baseline)); EXTERN(void) jpeg_add_quant_table JPP((j_compress_ptr cinfo, int which_tbl, const unsigned int *basic_table, int scale_factor, boolean force_baseline)); EXTERN(int) jpeg_quality_scaling JPP((int quality)); EXTERN(void) jpeg_simple_progression JPP((j_compress_ptr cinfo)); EXTERN(void) jpeg_suppress_tables JPP((j_compress_ptr cinfo, boolean suppress)); EXTERN(JQUANT_TBL *) jpeg_alloc_quant_table JPP((j_common_ptr cinfo)); EXTERN(JHUFF_TBL *) jpeg_alloc_huff_table JPP((j_common_ptr cinfo)); /* Main entry points for compression */ EXTERN(void) jpeg_start_compress JPP((j_compress_ptr cinfo, boolean write_all_tables)); EXTERN(JDIMENSION) jpeg_write_scanlines JPP((j_compress_ptr cinfo, JSAMPARRAY scanlines, JDIMENSION num_lines)); EXTERN(void) jpeg_finish_compress JPP((j_compress_ptr cinfo)); /* Precalculate JPEG dimensions for current compression parameters. */ EXTERN(void) jpeg_calc_jpeg_dimensions JPP((j_compress_ptr cinfo)); /* Replaces jpeg_write_scanlines when writing raw downsampled data. */ EXTERN(JDIMENSION) jpeg_write_raw_data JPP((j_compress_ptr cinfo, JSAMPIMAGE data, JDIMENSION num_lines)); /* Write a special marker. See libjpeg.txt concerning safe usage. */ EXTERN(void) jpeg_write_marker JPP((j_compress_ptr cinfo, int marker, const JOCTET * dataptr, unsigned int datalen)); /* Same, but piecemeal. */ EXTERN(void) jpeg_write_m_header JPP((j_compress_ptr cinfo, int marker, unsigned int datalen)); EXTERN(void) jpeg_write_m_byte JPP((j_compress_ptr cinfo, int val)); /* Alternate compression function: just write an abbreviated table file */ EXTERN(void) jpeg_write_tables JPP((j_compress_ptr cinfo)); /* Decompression startup: read start of JPEG datastream to see what's there */ EXTERN(int) jpeg_read_header JPP((j_decompress_ptr cinfo, boolean require_image)); /* Return value is one of: */ #define JPEG_SUSPENDED 0 /* Suspended due to lack of input data */ #define JPEG_HEADER_OK 1 /* Found valid image datastream */ #define JPEG_HEADER_TABLES_ONLY 2 /* Found valid table-specs-only datastream */ /* If you pass require_image = TRUE (normal case), you need not check for * a TABLES_ONLY return code; an abbreviated file will cause an error exit. * JPEG_SUSPENDED is only possible if you use a data source module that can * give a suspension return (the stdio source module doesn't). */ /* Main entry points for decompression */ EXTERN(boolean) jpeg_start_decompress JPP((j_decompress_ptr cinfo)); EXTERN(JDIMENSION) jpeg_read_scanlines JPP((j_decompress_ptr cinfo, JSAMPARRAY scanlines, JDIMENSION max_lines)); EXTERN(boolean) jpeg_finish_decompress JPP((j_decompress_ptr cinfo)); /* Replaces jpeg_read_scanlines when reading raw downsampled data. */ EXTERN(JDIMENSION) jpeg_read_raw_data JPP((j_decompress_ptr cinfo, JSAMPIMAGE data, JDIMENSION max_lines)); /* Additional entry points for buffered-image mode. */ EXTERN(boolean) jpeg_has_multiple_scans JPP((j_decompress_ptr cinfo)); EXTERN(boolean) jpeg_start_output JPP((j_decompress_ptr cinfo, int scan_number)); EXTERN(boolean) jpeg_finish_output JPP((j_decompress_ptr cinfo)); EXTERN(boolean) jpeg_input_complete JPP((j_decompress_ptr cinfo)); EXTERN(void) jpeg_new_colormap JPP((j_decompress_ptr cinfo)); EXTERN(int) jpeg_consume_input JPP((j_decompress_ptr cinfo)); /* Return value is one of: */ /* #define JPEG_SUSPENDED 0 Suspended due to lack of input data */ #define JPEG_REACHED_SOS 1 /* Reached start of new scan */ #define JPEG_REACHED_EOI 2 /* Reached end of image */ #define JPEG_ROW_COMPLETED 3 /* Completed one iMCU row */ #define JPEG_SCAN_COMPLETED 4 /* Completed last iMCU row of a scan */ /* Precalculate output dimensions for current decompression parameters. */ EXTERN(void) jpeg_core_output_dimensions JPP((j_decompress_ptr cinfo)); EXTERN(void) jpeg_calc_output_dimensions JPP((j_decompress_ptr cinfo)); /* Control saving of COM and APPn markers into marker_list. */ EXTERN(void) jpeg_save_markers JPP((j_decompress_ptr cinfo, int marker_code, unsigned int length_limit)); /* Install a special processing method for COM or APPn markers. */ EXTERN(void) jpeg_set_marker_processor JPP((j_decompress_ptr cinfo, int marker_code, jpeg_marker_parser_method routine)); /* Read or write raw DCT coefficients --- useful for lossless transcoding. */ EXTERN(jvirt_barray_ptr *) jpeg_read_coefficients JPP((j_decompress_ptr cinfo)); EXTERN(void) jpeg_write_coefficients JPP((j_compress_ptr cinfo, jvirt_barray_ptr * coef_arrays)); EXTERN(void) jpeg_copy_critical_parameters JPP((j_decompress_ptr srcinfo, j_compress_ptr dstinfo)); /* If you choose to abort compression or decompression before completing * jpeg_finish_(de)compress, then you need to clean up to release memory, * temporary files, etc. You can just call jpeg_destroy_(de)compress * if you're done with the JPEG object, but if you want to clean it up and * reuse it, call this: */ EXTERN(void) jpeg_abort_compress JPP((j_compress_ptr cinfo)); EXTERN(void) jpeg_abort_decompress JPP((j_decompress_ptr cinfo)); /* Generic versions of jpeg_abort and jpeg_destroy that work on either * flavor of JPEG object. These may be more convenient in some places. */ EXTERN(void) jpeg_abort JPP((j_common_ptr cinfo)); EXTERN(void) jpeg_destroy JPP((j_common_ptr cinfo)); /* Default restart-marker-resync procedure for use by data source modules */ EXTERN(boolean) jpeg_resync_to_restart JPP((j_decompress_ptr cinfo, int desired)); /* These marker codes are exported since applications and data source modules * are likely to want to use them. */ #define JPEG_RST0 0xD0 /* RST0 marker code */ #define JPEG_EOI 0xD9 /* EOI marker code */ #define JPEG_APP0 0xE0 /* APP0 marker code */ #define JPEG_COM 0xFE /* COM marker code */ /* If we have a brain-damaged compiler that emits warnings (or worse, errors) * for structure definitions that are never filled in, keep it quiet by * supplying dummy definitions for the various substructures. */ #ifdef INCOMPLETE_TYPES_BROKEN #ifndef JPEG_INTERNALS /* will be defined in jpegint.h */ struct jvirt_sarray_control { long dummy; }; struct jvirt_barray_control { long dummy; }; struct jpeg_comp_master { long dummy; }; struct jpeg_c_main_controller { long dummy; }; struct jpeg_c_prep_controller { long dummy; }; struct jpeg_c_coef_controller { long dummy; }; struct jpeg_marker_writer { long dummy; }; struct jpeg_color_converter { long dummy; }; struct jpeg_downsampler { long dummy; }; struct jpeg_forward_dct { long dummy; }; struct jpeg_entropy_encoder { long dummy; }; struct jpeg_decomp_master { long dummy; }; struct jpeg_d_main_controller { long dummy; }; struct jpeg_d_coef_controller { long dummy; }; struct jpeg_d_post_controller { long dummy; }; struct jpeg_input_controller { long dummy; }; struct jpeg_marker_reader { long dummy; }; struct jpeg_entropy_decoder { long dummy; }; struct jpeg_inverse_dct { long dummy; }; struct jpeg_upsampler { long dummy; }; struct jpeg_color_deconverter { long dummy; }; struct jpeg_color_quantizer { long dummy; }; #endif /* JPEG_INTERNALS */ #endif /* INCOMPLETE_TYPES_BROKEN */ /* * The JPEG library modules define JPEG_INTERNALS before including this file. * The internal structure declarations are read only when that is true. * Applications using the library should not include jpegint.h, but may wish * to include jerror.h. */ #ifdef JPEG_INTERNALS #include "jpegint.h" /* fetch private declarations */ #include "jerror.h" /* fetch error codes too */ #endif #ifdef __cplusplus #ifndef DONT_USE_EXTERN_C } #endif #endif #endif /* JPEGLIB_H */ fbi-2.10/jpeg/80/jinclude.h0000644000175000017500000000626212506525033013455 0ustar jmmjmm/* * jinclude.h * * Copyright (C) 1991-1994, Thomas G. Lane. * This file is part of the Independent JPEG Group's software. * For conditions of distribution and use, see the accompanying README file. * * This file exists to provide a single place to fix any problems with * including the wrong system include files. (Common problems are taken * care of by the standard jconfig symbols, but on really weird systems * you may have to edit this file.) * * NOTE: this file is NOT intended to be included by applications using the * JPEG library. Most applications need only include jpeglib.h. */ /* Include auto-config file to find out which system include files we need. */ #include "jconfig.h" /* auto configuration options */ #define JCONFIG_INCLUDED /* so that jpeglib.h doesn't do it again */ /* * We need the NULL macro and size_t typedef. * On an ANSI-conforming system it is sufficient to include . * Otherwise, we get them from or ; we may have to * pull in as well. * Note that the core JPEG library does not require ; * only the default error handler and data source/destination modules do. * But we must pull it in because of the references to FILE in jpeglib.h. * You can remove those references if you want to compile without . */ #ifdef HAVE_STDDEF_H #include #endif #ifdef HAVE_STDLIB_H #include #endif #ifdef NEED_SYS_TYPES_H #include #endif #include /* * We need memory copying and zeroing functions, plus strncpy(). * ANSI and System V implementations declare these in . * BSD doesn't have the mem() functions, but it does have bcopy()/bzero(). * Some systems may declare memset and memcpy in . * * NOTE: we assume the size parameters to these functions are of type size_t. * Change the casts in these macros if not! */ #ifdef NEED_BSD_STRINGS #include #define MEMZERO(target,size) bzero((void *)(target), (size_t)(size)) #define MEMCOPY(dest,src,size) bcopy((const void *)(src), (void *)(dest), (size_t)(size)) #else /* not BSD, assume ANSI/SysV string lib */ #include #define MEMZERO(target,size) memset((void *)(target), 0, (size_t)(size)) #define MEMCOPY(dest,src,size) memcpy((void *)(dest), (const void *)(src), (size_t)(size)) #endif /* * In ANSI C, and indeed any rational implementation, size_t is also the * type returned by sizeof(). However, it seems there are some irrational * implementations out there, in which sizeof() returns an int even though * size_t is defined as long or unsigned long. To ensure consistent results * we always use this SIZEOF() macro in place of using sizeof() directly. */ #define SIZEOF(object) ((size_t) sizeof(object)) /* * The modules that use fread() and fwrite() always invoke them through * these macros. On some systems you may need to twiddle the argument casts. * CAUTION: argument order is different from underlying functions! */ #define JFREAD(file,buf,sizeofbuf) \ ((size_t) fread((void *) (buf), (size_t) 1, (size_t) (sizeofbuf), (file))) #define JFWRITE(file,buf,sizeofbuf) \ ((size_t) fwrite((const void *) (buf), (size_t) 1, (size_t) (sizeofbuf), (file))) fbi-2.10/jpeg/80/transupp.h0000644000175000017500000002156112506525033013533 0ustar jmmjmm/* * transupp.h * * Copyright (C) 1997-2009, Thomas G. Lane, Guido Vollbeding. * This file is part of the Independent JPEG Group's software. * For conditions of distribution and use, see the accompanying README file. * * This file contains declarations for image transformation routines and * other utility code used by the jpegtran sample application. These are * NOT part of the core JPEG library. But we keep these routines separate * from jpegtran.c to ease the task of maintaining jpegtran-like programs * that have other user interfaces. * * NOTE: all the routines declared here have very specific requirements * about when they are to be executed during the reading and writing of the * source and destination files. See the comments in transupp.c, or see * jpegtran.c for an example of correct usage. */ /* If you happen not to want the image transform support, disable it here */ #ifndef TRANSFORMS_SUPPORTED #define TRANSFORMS_SUPPORTED 1 /* 0 disables transform code */ #endif /* * Although rotating and flipping data expressed as DCT coefficients is not * hard, there is an asymmetry in the JPEG format specification for images * whose dimensions aren't multiples of the iMCU size. The right and bottom * image edges are padded out to the next iMCU boundary with junk data; but * no padding is possible at the top and left edges. If we were to flip * the whole image including the pad data, then pad garbage would become * visible at the top and/or left, and real pixels would disappear into the * pad margins --- perhaps permanently, since encoders & decoders may not * bother to preserve DCT blocks that appear to be completely outside the * nominal image area. So, we have to exclude any partial iMCUs from the * basic transformation. * * Transpose is the only transformation that can handle partial iMCUs at the * right and bottom edges completely cleanly. flip_h can flip partial iMCUs * at the bottom, but leaves any partial iMCUs at the right edge untouched. * Similarly flip_v leaves any partial iMCUs at the bottom edge untouched. * The other transforms are defined as combinations of these basic transforms * and process edge blocks in a way that preserves the equivalence. * * The "trim" option causes untransformable partial iMCUs to be dropped; * this is not strictly lossless, but it usually gives the best-looking * result for odd-size images. Note that when this option is active, * the expected mathematical equivalences between the transforms may not hold. * (For example, -rot 270 -trim trims only the bottom edge, but -rot 90 -trim * followed by -rot 180 -trim trims both edges.) * * We also offer a lossless-crop option, which discards data outside a given * image region but losslessly preserves what is inside. Like the rotate and * flip transforms, lossless crop is restricted by the JPEG format: the upper * left corner of the selected region must fall on an iMCU boundary. If this * does not hold for the given crop parameters, we silently move the upper left * corner up and/or left to make it so, simultaneously increasing the region * dimensions to keep the lower right crop corner unchanged. (Thus, the * output image covers at least the requested region, but may cover more.) * * We also provide a lossless-resize option, which is kind of a lossless-crop * operation in the DCT coefficient block domain - it discards higher-order * coefficients and losslessly preserves lower-order coefficients of a * sub-block. * * Rotate/flip transform, resize, and crop can be requested together in a * single invocation. The crop is applied last --- that is, the crop region * is specified in terms of the destination image after transform/resize. * * We also offer a "force to grayscale" option, which simply discards the * chrominance channels of a YCbCr image. This is lossless in the sense that * the luminance channel is preserved exactly. It's not the same kind of * thing as the rotate/flip transformations, but it's convenient to handle it * as part of this package, mainly because the transformation routines have to * be aware of the option to know how many components to work on. */ /* Short forms of external names for systems with brain-damaged linkers. */ #ifdef NEED_SHORT_EXTERNAL_NAMES #define jtransform_parse_crop_spec jTrParCrop #define jtransform_request_workspace jTrRequest #define jtransform_adjust_parameters jTrAdjust #define jtransform_execute_transform jTrExec #define jtransform_perfect_transform jTrPerfect #define jcopy_markers_setup jCMrkSetup #define jcopy_markers_execute jCMrkExec #endif /* NEED_SHORT_EXTERNAL_NAMES */ /* * Codes for supported types of image transformations. */ typedef enum { JXFORM_NONE, /* no transformation */ JXFORM_FLIP_H, /* horizontal flip */ JXFORM_FLIP_V, /* vertical flip */ JXFORM_TRANSPOSE, /* transpose across UL-to-LR axis */ JXFORM_TRANSVERSE, /* transpose across UR-to-LL axis */ JXFORM_ROT_90, /* 90-degree clockwise rotation */ JXFORM_ROT_180, /* 180-degree rotation */ JXFORM_ROT_270 /* 270-degree clockwise (or 90 ccw) */ } JXFORM_CODE; /* * Codes for crop parameters, which can individually be unspecified, * positive, or negative. (Negative width or height makes no sense, though.) */ typedef enum { JCROP_UNSET, JCROP_POS, JCROP_NEG } JCROP_CODE; /* * Transform parameters struct. * NB: application must not change any elements of this struct after * calling jtransform_request_workspace. */ typedef struct { /* Options: set by caller */ JXFORM_CODE transform; /* image transform operator */ boolean perfect; /* if TRUE, fail if partial MCUs are requested */ boolean trim; /* if TRUE, trim partial MCUs as needed */ boolean force_grayscale; /* if TRUE, convert color image to grayscale */ boolean crop; /* if TRUE, crop source image */ /* Crop parameters: application need not set these unless crop is TRUE. * These can be filled in by jtransform_parse_crop_spec(). */ JDIMENSION crop_width; /* Width of selected region */ JCROP_CODE crop_width_set; JDIMENSION crop_height; /* Height of selected region */ JCROP_CODE crop_height_set; JDIMENSION crop_xoffset; /* X offset of selected region */ JCROP_CODE crop_xoffset_set; /* (negative measures from right edge) */ JDIMENSION crop_yoffset; /* Y offset of selected region */ JCROP_CODE crop_yoffset_set; /* (negative measures from bottom edge) */ /* Internal workspace: caller should not touch these */ int num_components; /* # of components in workspace */ jvirt_barray_ptr * workspace_coef_arrays; /* workspace for transformations */ JDIMENSION output_width; /* cropped destination dimensions */ JDIMENSION output_height; JDIMENSION x_crop_offset; /* destination crop offsets measured in iMCUs */ JDIMENSION y_crop_offset; int iMCU_sample_width; /* destination iMCU size */ int iMCU_sample_height; } jpeg_transform_info; #if TRANSFORMS_SUPPORTED /* Parse a crop specification (written in X11 geometry style) */ EXTERN(boolean) jtransform_parse_crop_spec JPP((jpeg_transform_info *info, const char *spec)); /* Request any required workspace */ EXTERN(boolean) jtransform_request_workspace JPP((j_decompress_ptr srcinfo, jpeg_transform_info *info)); /* Adjust output image parameters */ EXTERN(jvirt_barray_ptr *) jtransform_adjust_parameters JPP((j_decompress_ptr srcinfo, j_compress_ptr dstinfo, jvirt_barray_ptr *src_coef_arrays, jpeg_transform_info *info)); /* Execute the actual transformation, if any */ EXTERN(void) jtransform_execute_transform JPP((j_decompress_ptr srcinfo, j_compress_ptr dstinfo, jvirt_barray_ptr *src_coef_arrays, jpeg_transform_info *info)); /* Determine whether lossless transformation is perfectly * possible for a specified image and transformation. */ EXTERN(boolean) jtransform_perfect_transform JPP((JDIMENSION image_width, JDIMENSION image_height, int MCU_width, int MCU_height, JXFORM_CODE transform)); /* jtransform_execute_transform used to be called * jtransform_execute_transformation, but some compilers complain about * routine names that long. This macro is here to avoid breaking any * old source code that uses the original name... */ #define jtransform_execute_transformation jtransform_execute_transform #endif /* TRANSFORMS_SUPPORTED */ /* * Support for copying optional markers from source to destination file. */ typedef enum { JCOPYOPT_NONE, /* copy no optional markers */ JCOPYOPT_COMMENTS, /* copy only comment (COM) markers */ JCOPYOPT_ALL /* copy all optional markers */ } JCOPY_OPTION; #define JCOPYOPT_DEFAULT JCOPYOPT_COMMENTS /* recommended default */ /* Setup decompression object to save desired markers in memory */ EXTERN(void) jcopy_markers_setup JPP((j_decompress_ptr srcinfo, JCOPY_OPTION option)); /* Copy markers saved in the given source object to the destination object */ EXTERN(void) jcopy_markers_execute JPP((j_decompress_ptr srcinfo, j_compress_ptr dstinfo, JCOPY_OPTION option)); fbi-2.10/jpeg/80/jpegint.h0000644000175000017500000004012612506525033013315 0ustar jmmjmm/* * jpegint.h * * Copyright (C) 1991-1997, Thomas G. Lane. * Modified 1997-2009 by Guido Vollbeding. * This file is part of the Independent JPEG Group's software. * For conditions of distribution and use, see the accompanying README file. * * This file provides common declarations for the various JPEG modules. * These declarations are considered internal to the JPEG library; most * applications using the library shouldn't need to include this file. */ /* Declarations for both compression & decompression */ typedef enum { /* Operating modes for buffer controllers */ JBUF_PASS_THRU, /* Plain stripwise operation */ /* Remaining modes require a full-image buffer to have been created */ JBUF_SAVE_SOURCE, /* Run source subobject only, save output */ JBUF_CRANK_DEST, /* Run dest subobject only, using saved data */ JBUF_SAVE_AND_PASS /* Run both subobjects, save output */ } J_BUF_MODE; /* Values of global_state field (jdapi.c has some dependencies on ordering!) */ #define CSTATE_START 100 /* after create_compress */ #define CSTATE_SCANNING 101 /* start_compress done, write_scanlines OK */ #define CSTATE_RAW_OK 102 /* start_compress done, write_raw_data OK */ #define CSTATE_WRCOEFS 103 /* jpeg_write_coefficients done */ #define DSTATE_START 200 /* after create_decompress */ #define DSTATE_INHEADER 201 /* reading header markers, no SOS yet */ #define DSTATE_READY 202 /* found SOS, ready for start_decompress */ #define DSTATE_PRELOAD 203 /* reading multiscan file in start_decompress*/ #define DSTATE_PRESCAN 204 /* performing dummy pass for 2-pass quant */ #define DSTATE_SCANNING 205 /* start_decompress done, read_scanlines OK */ #define DSTATE_RAW_OK 206 /* start_decompress done, read_raw_data OK */ #define DSTATE_BUFIMAGE 207 /* expecting jpeg_start_output */ #define DSTATE_BUFPOST 208 /* looking for SOS/EOI in jpeg_finish_output */ #define DSTATE_RDCOEFS 209 /* reading file in jpeg_read_coefficients */ #define DSTATE_STOPPING 210 /* looking for EOI in jpeg_finish_decompress */ /* Declarations for compression modules */ /* Master control module */ struct jpeg_comp_master { JMETHOD(void, prepare_for_pass, (j_compress_ptr cinfo)); JMETHOD(void, pass_startup, (j_compress_ptr cinfo)); JMETHOD(void, finish_pass, (j_compress_ptr cinfo)); /* State variables made visible to other modules */ boolean call_pass_startup; /* True if pass_startup must be called */ boolean is_last_pass; /* True during last pass */ }; /* Main buffer control (downsampled-data buffer) */ struct jpeg_c_main_controller { JMETHOD(void, start_pass, (j_compress_ptr cinfo, J_BUF_MODE pass_mode)); JMETHOD(void, process_data, (j_compress_ptr cinfo, JSAMPARRAY input_buf, JDIMENSION *in_row_ctr, JDIMENSION in_rows_avail)); }; /* Compression preprocessing (downsampling input buffer control) */ struct jpeg_c_prep_controller { JMETHOD(void, start_pass, (j_compress_ptr cinfo, J_BUF_MODE pass_mode)); JMETHOD(void, pre_process_data, (j_compress_ptr cinfo, JSAMPARRAY input_buf, JDIMENSION *in_row_ctr, JDIMENSION in_rows_avail, JSAMPIMAGE output_buf, JDIMENSION *out_row_group_ctr, JDIMENSION out_row_groups_avail)); }; /* Coefficient buffer control */ struct jpeg_c_coef_controller { JMETHOD(void, start_pass, (j_compress_ptr cinfo, J_BUF_MODE pass_mode)); JMETHOD(boolean, compress_data, (j_compress_ptr cinfo, JSAMPIMAGE input_buf)); }; /* Colorspace conversion */ struct jpeg_color_converter { JMETHOD(void, start_pass, (j_compress_ptr cinfo)); JMETHOD(void, color_convert, (j_compress_ptr cinfo, JSAMPARRAY input_buf, JSAMPIMAGE output_buf, JDIMENSION output_row, int num_rows)); }; /* Downsampling */ struct jpeg_downsampler { JMETHOD(void, start_pass, (j_compress_ptr cinfo)); JMETHOD(void, downsample, (j_compress_ptr cinfo, JSAMPIMAGE input_buf, JDIMENSION in_row_index, JSAMPIMAGE output_buf, JDIMENSION out_row_group_index)); boolean need_context_rows; /* TRUE if need rows above & below */ }; /* Forward DCT (also controls coefficient quantization) */ typedef JMETHOD(void, forward_DCT_ptr, (j_compress_ptr cinfo, jpeg_component_info * compptr, JSAMPARRAY sample_data, JBLOCKROW coef_blocks, JDIMENSION start_row, JDIMENSION start_col, JDIMENSION num_blocks)); struct jpeg_forward_dct { JMETHOD(void, start_pass, (j_compress_ptr cinfo)); /* It is useful to allow each component to have a separate FDCT method. */ forward_DCT_ptr forward_DCT[MAX_COMPONENTS]; }; /* Entropy encoding */ struct jpeg_entropy_encoder { JMETHOD(void, start_pass, (j_compress_ptr cinfo, boolean gather_statistics)); JMETHOD(boolean, encode_mcu, (j_compress_ptr cinfo, JBLOCKROW *MCU_data)); JMETHOD(void, finish_pass, (j_compress_ptr cinfo)); }; /* Marker writing */ struct jpeg_marker_writer { JMETHOD(void, write_file_header, (j_compress_ptr cinfo)); JMETHOD(void, write_frame_header, (j_compress_ptr cinfo)); JMETHOD(void, write_scan_header, (j_compress_ptr cinfo)); JMETHOD(void, write_file_trailer, (j_compress_ptr cinfo)); JMETHOD(void, write_tables_only, (j_compress_ptr cinfo)); /* These routines are exported to allow insertion of extra markers */ /* Probably only COM and APPn markers should be written this way */ JMETHOD(void, write_marker_header, (j_compress_ptr cinfo, int marker, unsigned int datalen)); JMETHOD(void, write_marker_byte, (j_compress_ptr cinfo, int val)); }; /* Declarations for decompression modules */ /* Master control module */ struct jpeg_decomp_master { JMETHOD(void, prepare_for_output_pass, (j_decompress_ptr cinfo)); JMETHOD(void, finish_output_pass, (j_decompress_ptr cinfo)); /* State variables made visible to other modules */ boolean is_dummy_pass; /* True during 1st pass for 2-pass quant */ }; /* Input control module */ struct jpeg_input_controller { JMETHOD(int, consume_input, (j_decompress_ptr cinfo)); JMETHOD(void, reset_input_controller, (j_decompress_ptr cinfo)); JMETHOD(void, start_input_pass, (j_decompress_ptr cinfo)); JMETHOD(void, finish_input_pass, (j_decompress_ptr cinfo)); /* State variables made visible to other modules */ boolean has_multiple_scans; /* True if file has multiple scans */ boolean eoi_reached; /* True when EOI has been consumed */ }; /* Main buffer control (downsampled-data buffer) */ struct jpeg_d_main_controller { JMETHOD(void, start_pass, (j_decompress_ptr cinfo, J_BUF_MODE pass_mode)); JMETHOD(void, process_data, (j_decompress_ptr cinfo, JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, JDIMENSION out_rows_avail)); }; /* Coefficient buffer control */ struct jpeg_d_coef_controller { JMETHOD(void, start_input_pass, (j_decompress_ptr cinfo)); JMETHOD(int, consume_data, (j_decompress_ptr cinfo)); JMETHOD(void, start_output_pass, (j_decompress_ptr cinfo)); JMETHOD(int, decompress_data, (j_decompress_ptr cinfo, JSAMPIMAGE output_buf)); /* Pointer to array of coefficient virtual arrays, or NULL if none */ jvirt_barray_ptr *coef_arrays; }; /* Decompression postprocessing (color quantization buffer control) */ struct jpeg_d_post_controller { JMETHOD(void, start_pass, (j_decompress_ptr cinfo, J_BUF_MODE pass_mode)); JMETHOD(void, post_process_data, (j_decompress_ptr cinfo, JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr, JDIMENSION in_row_groups_avail, JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, JDIMENSION out_rows_avail)); }; /* Marker reading & parsing */ struct jpeg_marker_reader { JMETHOD(void, reset_marker_reader, (j_decompress_ptr cinfo)); /* Read markers until SOS or EOI. * Returns same codes as are defined for jpeg_consume_input: * JPEG_SUSPENDED, JPEG_REACHED_SOS, or JPEG_REACHED_EOI. */ JMETHOD(int, read_markers, (j_decompress_ptr cinfo)); /* Read a restart marker --- exported for use by entropy decoder only */ jpeg_marker_parser_method read_restart_marker; /* State of marker reader --- nominally internal, but applications * supplying COM or APPn handlers might like to know the state. */ boolean saw_SOI; /* found SOI? */ boolean saw_SOF; /* found SOF? */ int next_restart_num; /* next restart number expected (0-7) */ unsigned int discarded_bytes; /* # of bytes skipped looking for a marker */ }; /* Entropy decoding */ struct jpeg_entropy_decoder { JMETHOD(void, start_pass, (j_decompress_ptr cinfo)); JMETHOD(boolean, decode_mcu, (j_decompress_ptr cinfo, JBLOCKROW *MCU_data)); }; /* Inverse DCT (also performs dequantization) */ typedef JMETHOD(void, inverse_DCT_method_ptr, (j_decompress_ptr cinfo, jpeg_component_info * compptr, JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); struct jpeg_inverse_dct { JMETHOD(void, start_pass, (j_decompress_ptr cinfo)); /* It is useful to allow each component to have a separate IDCT method. */ inverse_DCT_method_ptr inverse_DCT[MAX_COMPONENTS]; }; /* Upsampling (note that upsampler must also call color converter) */ struct jpeg_upsampler { JMETHOD(void, start_pass, (j_decompress_ptr cinfo)); JMETHOD(void, upsample, (j_decompress_ptr cinfo, JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr, JDIMENSION in_row_groups_avail, JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, JDIMENSION out_rows_avail)); boolean need_context_rows; /* TRUE if need rows above & below */ }; /* Colorspace conversion */ struct jpeg_color_deconverter { JMETHOD(void, start_pass, (j_decompress_ptr cinfo)); JMETHOD(void, color_convert, (j_decompress_ptr cinfo, JSAMPIMAGE input_buf, JDIMENSION input_row, JSAMPARRAY output_buf, int num_rows)); }; /* Color quantization or color precision reduction */ struct jpeg_color_quantizer { JMETHOD(void, start_pass, (j_decompress_ptr cinfo, boolean is_pre_scan)); JMETHOD(void, color_quantize, (j_decompress_ptr cinfo, JSAMPARRAY input_buf, JSAMPARRAY output_buf, int num_rows)); JMETHOD(void, finish_pass, (j_decompress_ptr cinfo)); JMETHOD(void, new_color_map, (j_decompress_ptr cinfo)); }; /* Miscellaneous useful macros */ #undef MAX #define MAX(a,b) ((a) > (b) ? (a) : (b)) #undef MIN #define MIN(a,b) ((a) < (b) ? (a) : (b)) /* We assume that right shift corresponds to signed division by 2 with * rounding towards minus infinity. This is correct for typical "arithmetic * shift" instructions that shift in copies of the sign bit. But some * C compilers implement >> with an unsigned shift. For these machines you * must define RIGHT_SHIFT_IS_UNSIGNED. * RIGHT_SHIFT provides a proper signed right shift of an INT32 quantity. * It is only applied with constant shift counts. SHIFT_TEMPS must be * included in the variables of any routine using RIGHT_SHIFT. */ #ifdef RIGHT_SHIFT_IS_UNSIGNED #define SHIFT_TEMPS INT32 shift_temp; #define RIGHT_SHIFT(x,shft) \ ((shift_temp = (x)) < 0 ? \ (shift_temp >> (shft)) | ((~((INT32) 0)) << (32-(shft))) : \ (shift_temp >> (shft))) #else #define SHIFT_TEMPS #define RIGHT_SHIFT(x,shft) ((x) >> (shft)) #endif /* Short forms of external names for systems with brain-damaged linkers. */ #ifdef NEED_SHORT_EXTERNAL_NAMES #define jinit_compress_master jICompress #define jinit_c_master_control jICMaster #define jinit_c_main_controller jICMainC #define jinit_c_prep_controller jICPrepC #define jinit_c_coef_controller jICCoefC #define jinit_color_converter jICColor #define jinit_downsampler jIDownsampler #define jinit_forward_dct jIFDCT #define jinit_huff_encoder jIHEncoder #define jinit_arith_encoder jIAEncoder #define jinit_marker_writer jIMWriter #define jinit_master_decompress jIDMaster #define jinit_d_main_controller jIDMainC #define jinit_d_coef_controller jIDCoefC #define jinit_d_post_controller jIDPostC #define jinit_input_controller jIInCtlr #define jinit_marker_reader jIMReader #define jinit_huff_decoder jIHDecoder #define jinit_arith_decoder jIADecoder #define jinit_inverse_dct jIIDCT #define jinit_upsampler jIUpsampler #define jinit_color_deconverter jIDColor #define jinit_1pass_quantizer jI1Quant #define jinit_2pass_quantizer jI2Quant #define jinit_merged_upsampler jIMUpsampler #define jinit_memory_mgr jIMemMgr #define jdiv_round_up jDivRound #define jround_up jRound #define jcopy_sample_rows jCopySamples #define jcopy_block_row jCopyBlocks #define jzero_far jZeroFar #define jpeg_zigzag_order jZIGTable #define jpeg_natural_order jZAGTable #define jpeg_natural_order7 jZAGTable7 #define jpeg_natural_order6 jZAGTable6 #define jpeg_natural_order5 jZAGTable5 #define jpeg_natural_order4 jZAGTable4 #define jpeg_natural_order3 jZAGTable3 #define jpeg_natural_order2 jZAGTable2 #define jpeg_aritab jAriTab #endif /* NEED_SHORT_EXTERNAL_NAMES */ /* Compression module initialization routines */ EXTERN(void) jinit_compress_master JPP((j_compress_ptr cinfo)); EXTERN(void) jinit_c_master_control JPP((j_compress_ptr cinfo, boolean transcode_only)); EXTERN(void) jinit_c_main_controller JPP((j_compress_ptr cinfo, boolean need_full_buffer)); EXTERN(void) jinit_c_prep_controller JPP((j_compress_ptr cinfo, boolean need_full_buffer)); EXTERN(void) jinit_c_coef_controller JPP((j_compress_ptr cinfo, boolean need_full_buffer)); EXTERN(void) jinit_color_converter JPP((j_compress_ptr cinfo)); EXTERN(void) jinit_downsampler JPP((j_compress_ptr cinfo)); EXTERN(void) jinit_forward_dct JPP((j_compress_ptr cinfo)); EXTERN(void) jinit_huff_encoder JPP((j_compress_ptr cinfo)); EXTERN(void) jinit_arith_encoder JPP((j_compress_ptr cinfo)); EXTERN(void) jinit_marker_writer JPP((j_compress_ptr cinfo)); /* Decompression module initialization routines */ EXTERN(void) jinit_master_decompress JPP((j_decompress_ptr cinfo)); EXTERN(void) jinit_d_main_controller JPP((j_decompress_ptr cinfo, boolean need_full_buffer)); EXTERN(void) jinit_d_coef_controller JPP((j_decompress_ptr cinfo, boolean need_full_buffer)); EXTERN(void) jinit_d_post_controller JPP((j_decompress_ptr cinfo, boolean need_full_buffer)); EXTERN(void) jinit_input_controller JPP((j_decompress_ptr cinfo)); EXTERN(void) jinit_marker_reader JPP((j_decompress_ptr cinfo)); EXTERN(void) jinit_huff_decoder JPP((j_decompress_ptr cinfo)); EXTERN(void) jinit_arith_decoder JPP((j_decompress_ptr cinfo)); EXTERN(void) jinit_inverse_dct JPP((j_decompress_ptr cinfo)); EXTERN(void) jinit_upsampler JPP((j_decompress_ptr cinfo)); EXTERN(void) jinit_color_deconverter JPP((j_decompress_ptr cinfo)); EXTERN(void) jinit_1pass_quantizer JPP((j_decompress_ptr cinfo)); EXTERN(void) jinit_2pass_quantizer JPP((j_decompress_ptr cinfo)); EXTERN(void) jinit_merged_upsampler JPP((j_decompress_ptr cinfo)); /* Memory manager initialization */ EXTERN(void) jinit_memory_mgr JPP((j_common_ptr cinfo)); /* Utility routines in jutils.c */ EXTERN(long) jdiv_round_up JPP((long a, long b)); EXTERN(long) jround_up JPP((long a, long b)); EXTERN(void) jcopy_sample_rows JPP((JSAMPARRAY input_array, int source_row, JSAMPARRAY output_array, int dest_row, int num_rows, JDIMENSION num_cols)); EXTERN(void) jcopy_block_row JPP((JBLOCKROW input_row, JBLOCKROW output_row, JDIMENSION num_blocks)); EXTERN(void) jzero_far JPP((void FAR * target, size_t bytestozero)); /* Constant tables in jutils.c */ #if 0 /* This table is not actually needed in v6a */ extern const int jpeg_zigzag_order[]; /* natural coef order to zigzag order */ #endif extern const int jpeg_natural_order[]; /* zigzag coef order to natural order */ extern const int jpeg_natural_order7[]; /* zz to natural order for 7x7 block */ extern const int jpeg_natural_order6[]; /* zz to natural order for 6x6 block */ extern const int jpeg_natural_order5[]; /* zz to natural order for 5x5 block */ extern const int jpeg_natural_order4[]; /* zz to natural order for 4x4 block */ extern const int jpeg_natural_order3[]; /* zz to natural order for 3x3 block */ extern const int jpeg_natural_order2[]; /* zz to natural order for 2x2 block */ /* Arithmetic coding probability estimation tables in jaricom.c */ extern const INT32 jpeg_aritab[]; /* Suppress undefined-structure complaints if necessary. */ #ifdef INCOMPLETE_TYPES_BROKEN #ifndef AM_MEMORY_MANAGER /* only jmemmgr.c defines these */ struct jvirt_sarray_control { long dummy; }; struct jvirt_barray_control { long dummy; }; #endif #endif /* INCOMPLETE_TYPES_BROKEN */ fbi-2.10/jpeg/62/0000755000175000017500000000000012506525033011501 5ustar jmmjmmfbi-2.10/jpeg/62/transupp.c0000644000175000017500000007756612506525033013546 0ustar jmmjmm/* * transupp.c * * Copyright (C) 1997, Thomas G. Lane. * This file is part of the Independent JPEG Group's software. * For conditions of distribution and use, see the accompanying README file. * * This file contains image transformation routines and other utility code * used by the jpegtran sample application. These are NOT part of the core * JPEG library. But we keep these routines separate from jpegtran.c to * ease the task of maintaining jpegtran-like programs that have other user * interfaces. */ /* Although this file really shouldn't have access to the library internals, * it's helpful to let it call jround_up() and jcopy_block_row(). */ #define JPEG_INTERNALS #include "jinclude.h" #include "jpeglib.h" #include "transupp.h" /* My own external interface */ #if TRANSFORMS_SUPPORTED /* * Lossless image transformation routines. These routines work on DCT * coefficient arrays and thus do not require any lossy decompression * or recompression of the image. * Thanks to Guido Vollbeding for the initial design and code of this feature. * * Horizontal flipping is done in-place, using a single top-to-bottom * pass through the virtual source array. It will thus be much the * fastest option for images larger than main memory. * * The other routines require a set of destination virtual arrays, so they * need twice as much memory as jpegtran normally does. The destination * arrays are always written in normal scan order (top to bottom) because * the virtual array manager expects this. The source arrays will be scanned * in the corresponding order, which means multiple passes through the source * arrays for most of the transforms. That could result in much thrashing * if the image is larger than main memory. * * Some notes about the operating environment of the individual transform * routines: * 1. Both the source and destination virtual arrays are allocated from the * source JPEG object, and therefore should be manipulated by calling the * source's memory manager. * 2. The destination's component count should be used. It may be smaller * than the source's when forcing to grayscale. * 3. Likewise the destination's sampling factors should be used. When * forcing to grayscale the destination's sampling factors will be all 1, * and we may as well take that as the effective iMCU size. * 4. When "trim" is in effect, the destination's dimensions will be the * trimmed values but the source's will be untrimmed. * 5. All the routines assume that the source and destination buffers are * padded out to a full iMCU boundary. This is true, although for the * source buffer it is an undocumented property of jdcoefct.c. * Notes 2,3,4 boil down to this: generally we should use the destination's * dimensions and ignore the source's. */ LOCAL(void) do_flip_h (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, jvirt_barray_ptr *src_coef_arrays) /* Horizontal flip; done in-place, so no separate dest array is required */ { JDIMENSION MCU_cols, comp_width, blk_x, blk_y; int ci, k, offset_y; JBLOCKARRAY buffer; JCOEFPTR ptr1, ptr2; JCOEF temp1, temp2; jpeg_component_info *compptr; /* Horizontal mirroring of DCT blocks is accomplished by swapping * pairs of blocks in-place. Within a DCT block, we perform horizontal * mirroring by changing the signs of odd-numbered columns. * Partial iMCUs at the right edge are left untouched. */ MCU_cols = dstinfo->image_width / (dstinfo->max_h_samp_factor * DCTSIZE); for (ci = 0; ci < dstinfo->num_components; ci++) { compptr = dstinfo->comp_info + ci; comp_width = MCU_cols * compptr->h_samp_factor; for (blk_y = 0; blk_y < compptr->height_in_blocks; blk_y += compptr->v_samp_factor) { buffer = (*srcinfo->mem->access_virt_barray) ((j_common_ptr) srcinfo, src_coef_arrays[ci], blk_y, (JDIMENSION) compptr->v_samp_factor, TRUE); for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { for (blk_x = 0; blk_x * 2 < comp_width; blk_x++) { ptr1 = buffer[offset_y][blk_x]; ptr2 = buffer[offset_y][comp_width - blk_x - 1]; /* this unrolled loop doesn't need to know which row it's on... */ for (k = 0; k < DCTSIZE2; k += 2) { temp1 = *ptr1; /* swap even column */ temp2 = *ptr2; *ptr1++ = temp2; *ptr2++ = temp1; temp1 = *ptr1; /* swap odd column with sign change */ temp2 = *ptr2; *ptr1++ = -temp2; *ptr2++ = -temp1; } } } } } } LOCAL(void) do_flip_v (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, jvirt_barray_ptr *src_coef_arrays, jvirt_barray_ptr *dst_coef_arrays) /* Vertical flip */ { JDIMENSION MCU_rows, comp_height, dst_blk_x, dst_blk_y; int ci, i, j, offset_y; JBLOCKARRAY src_buffer, dst_buffer; JBLOCKROW src_row_ptr, dst_row_ptr; JCOEFPTR src_ptr, dst_ptr; jpeg_component_info *compptr; /* We output into a separate array because we can't touch different * rows of the source virtual array simultaneously. Otherwise, this * is a pretty straightforward analog of horizontal flip. * Within a DCT block, vertical mirroring is done by changing the signs * of odd-numbered rows. * Partial iMCUs at the bottom edge are copied verbatim. */ MCU_rows = dstinfo->image_height / (dstinfo->max_v_samp_factor * DCTSIZE); for (ci = 0; ci < dstinfo->num_components; ci++) { compptr = dstinfo->comp_info + ci; comp_height = MCU_rows * compptr->v_samp_factor; for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; dst_blk_y += compptr->v_samp_factor) { dst_buffer = (*srcinfo->mem->access_virt_barray) ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y, (JDIMENSION) compptr->v_samp_factor, TRUE); if (dst_blk_y < comp_height) { /* Row is within the mirrorable area. */ src_buffer = (*srcinfo->mem->access_virt_barray) ((j_common_ptr) srcinfo, src_coef_arrays[ci], comp_height - dst_blk_y - (JDIMENSION) compptr->v_samp_factor, (JDIMENSION) compptr->v_samp_factor, FALSE); } else { /* Bottom-edge blocks will be copied verbatim. */ src_buffer = (*srcinfo->mem->access_virt_barray) ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_y, (JDIMENSION) compptr->v_samp_factor, FALSE); } for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { if (dst_blk_y < comp_height) { /* Row is within the mirrorable area. */ dst_row_ptr = dst_buffer[offset_y]; src_row_ptr = src_buffer[compptr->v_samp_factor - offset_y - 1]; for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; dst_blk_x++) { dst_ptr = dst_row_ptr[dst_blk_x]; src_ptr = src_row_ptr[dst_blk_x]; for (i = 0; i < DCTSIZE; i += 2) { /* copy even row */ for (j = 0; j < DCTSIZE; j++) *dst_ptr++ = *src_ptr++; /* copy odd row with sign change */ for (j = 0; j < DCTSIZE; j++) *dst_ptr++ = - *src_ptr++; } } } else { /* Just copy row verbatim. */ jcopy_block_row(src_buffer[offset_y], dst_buffer[offset_y], compptr->width_in_blocks); } } } } } LOCAL(void) do_transpose (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, jvirt_barray_ptr *src_coef_arrays, jvirt_barray_ptr *dst_coef_arrays) /* Transpose source into destination */ { JDIMENSION dst_blk_x, dst_blk_y; int ci, i, j, offset_x, offset_y; JBLOCKARRAY src_buffer, dst_buffer; JCOEFPTR src_ptr, dst_ptr; jpeg_component_info *compptr; /* Transposing pixels within a block just requires transposing the * DCT coefficients. * Partial iMCUs at the edges require no special treatment; we simply * process all the available DCT blocks for every component. */ for (ci = 0; ci < dstinfo->num_components; ci++) { compptr = dstinfo->comp_info + ci; for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; dst_blk_y += compptr->v_samp_factor) { dst_buffer = (*srcinfo->mem->access_virt_barray) ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y, (JDIMENSION) compptr->v_samp_factor, TRUE); for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; dst_blk_x += compptr->h_samp_factor) { src_buffer = (*srcinfo->mem->access_virt_barray) ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_x, (JDIMENSION) compptr->h_samp_factor, FALSE); for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) { src_ptr = src_buffer[offset_x][dst_blk_y + offset_y]; dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x]; for (i = 0; i < DCTSIZE; i++) for (j = 0; j < DCTSIZE; j++) dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; } } } } } } LOCAL(void) do_rot_90 (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, jvirt_barray_ptr *src_coef_arrays, jvirt_barray_ptr *dst_coef_arrays) /* 90 degree rotation is equivalent to * 1. Transposing the image; * 2. Horizontal mirroring. * These two steps are merged into a single processing routine. */ { JDIMENSION MCU_cols, comp_width, dst_blk_x, dst_blk_y; int ci, i, j, offset_x, offset_y; JBLOCKARRAY src_buffer, dst_buffer; JCOEFPTR src_ptr, dst_ptr; jpeg_component_info *compptr; /* Because of the horizontal mirror step, we can't process partial iMCUs * at the (output) right edge properly. They just get transposed and * not mirrored. */ MCU_cols = dstinfo->image_width / (dstinfo->max_h_samp_factor * DCTSIZE); for (ci = 0; ci < dstinfo->num_components; ci++) { compptr = dstinfo->comp_info + ci; comp_width = MCU_cols * compptr->h_samp_factor; for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; dst_blk_y += compptr->v_samp_factor) { dst_buffer = (*srcinfo->mem->access_virt_barray) ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y, (JDIMENSION) compptr->v_samp_factor, TRUE); for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; dst_blk_x += compptr->h_samp_factor) { src_buffer = (*srcinfo->mem->access_virt_barray) ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_x, (JDIMENSION) compptr->h_samp_factor, FALSE); for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) { src_ptr = src_buffer[offset_x][dst_blk_y + offset_y]; if (dst_blk_x < comp_width) { /* Block is within the mirrorable area. */ dst_ptr = dst_buffer[offset_y] [comp_width - dst_blk_x - offset_x - 1]; for (i = 0; i < DCTSIZE; i++) { for (j = 0; j < DCTSIZE; j++) dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; i++; for (j = 0; j < DCTSIZE; j++) dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j]; } } else { /* Edge blocks are transposed but not mirrored. */ dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x]; for (i = 0; i < DCTSIZE; i++) for (j = 0; j < DCTSIZE; j++) dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; } } } } } } } LOCAL(void) do_rot_270 (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, jvirt_barray_ptr *src_coef_arrays, jvirt_barray_ptr *dst_coef_arrays) /* 270 degree rotation is equivalent to * 1. Horizontal mirroring; * 2. Transposing the image. * These two steps are merged into a single processing routine. */ { JDIMENSION MCU_rows, comp_height, dst_blk_x, dst_blk_y; int ci, i, j, offset_x, offset_y; JBLOCKARRAY src_buffer, dst_buffer; JCOEFPTR src_ptr, dst_ptr; jpeg_component_info *compptr; /* Because of the horizontal mirror step, we can't process partial iMCUs * at the (output) bottom edge properly. They just get transposed and * not mirrored. */ MCU_rows = dstinfo->image_height / (dstinfo->max_v_samp_factor * DCTSIZE); for (ci = 0; ci < dstinfo->num_components; ci++) { compptr = dstinfo->comp_info + ci; comp_height = MCU_rows * compptr->v_samp_factor; for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; dst_blk_y += compptr->v_samp_factor) { dst_buffer = (*srcinfo->mem->access_virt_barray) ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y, (JDIMENSION) compptr->v_samp_factor, TRUE); for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; dst_blk_x += compptr->h_samp_factor) { src_buffer = (*srcinfo->mem->access_virt_barray) ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_x, (JDIMENSION) compptr->h_samp_factor, FALSE); for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) { dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x]; if (dst_blk_y < comp_height) { /* Block is within the mirrorable area. */ src_ptr = src_buffer[offset_x] [comp_height - dst_blk_y - offset_y - 1]; for (i = 0; i < DCTSIZE; i++) { for (j = 0; j < DCTSIZE; j++) { dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; j++; dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j]; } } } else { /* Edge blocks are transposed but not mirrored. */ src_ptr = src_buffer[offset_x][dst_blk_y + offset_y]; for (i = 0; i < DCTSIZE; i++) for (j = 0; j < DCTSIZE; j++) dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; } } } } } } } LOCAL(void) do_rot_180 (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, jvirt_barray_ptr *src_coef_arrays, jvirt_barray_ptr *dst_coef_arrays) /* 180 degree rotation is equivalent to * 1. Vertical mirroring; * 2. Horizontal mirroring. * These two steps are merged into a single processing routine. */ { JDIMENSION MCU_cols, MCU_rows, comp_width, comp_height, dst_blk_x, dst_blk_y; int ci, i, j, offset_y; JBLOCKARRAY src_buffer, dst_buffer; JBLOCKROW src_row_ptr, dst_row_ptr; JCOEFPTR src_ptr, dst_ptr; jpeg_component_info *compptr; MCU_cols = dstinfo->image_width / (dstinfo->max_h_samp_factor * DCTSIZE); MCU_rows = dstinfo->image_height / (dstinfo->max_v_samp_factor * DCTSIZE); for (ci = 0; ci < dstinfo->num_components; ci++) { compptr = dstinfo->comp_info + ci; comp_width = MCU_cols * compptr->h_samp_factor; comp_height = MCU_rows * compptr->v_samp_factor; for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; dst_blk_y += compptr->v_samp_factor) { dst_buffer = (*srcinfo->mem->access_virt_barray) ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y, (JDIMENSION) compptr->v_samp_factor, TRUE); if (dst_blk_y < comp_height) { /* Row is within the vertically mirrorable area. */ src_buffer = (*srcinfo->mem->access_virt_barray) ((j_common_ptr) srcinfo, src_coef_arrays[ci], comp_height - dst_blk_y - (JDIMENSION) compptr->v_samp_factor, (JDIMENSION) compptr->v_samp_factor, FALSE); } else { /* Bottom-edge rows are only mirrored horizontally. */ src_buffer = (*srcinfo->mem->access_virt_barray) ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_y, (JDIMENSION) compptr->v_samp_factor, FALSE); } for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { if (dst_blk_y < comp_height) { /* Row is within the mirrorable area. */ dst_row_ptr = dst_buffer[offset_y]; src_row_ptr = src_buffer[compptr->v_samp_factor - offset_y - 1]; /* Process the blocks that can be mirrored both ways. */ for (dst_blk_x = 0; dst_blk_x < comp_width; dst_blk_x++) { dst_ptr = dst_row_ptr[dst_blk_x]; src_ptr = src_row_ptr[comp_width - dst_blk_x - 1]; for (i = 0; i < DCTSIZE; i += 2) { /* For even row, negate every odd column. */ for (j = 0; j < DCTSIZE; j += 2) { *dst_ptr++ = *src_ptr++; *dst_ptr++ = - *src_ptr++; } /* For odd row, negate every even column. */ for (j = 0; j < DCTSIZE; j += 2) { *dst_ptr++ = - *src_ptr++; *dst_ptr++ = *src_ptr++; } } } /* Any remaining right-edge blocks are only mirrored vertically. */ for (; dst_blk_x < compptr->width_in_blocks; dst_blk_x++) { dst_ptr = dst_row_ptr[dst_blk_x]; src_ptr = src_row_ptr[dst_blk_x]; for (i = 0; i < DCTSIZE; i += 2) { for (j = 0; j < DCTSIZE; j++) *dst_ptr++ = *src_ptr++; for (j = 0; j < DCTSIZE; j++) *dst_ptr++ = - *src_ptr++; } } } else { /* Remaining rows are just mirrored horizontally. */ dst_row_ptr = dst_buffer[offset_y]; src_row_ptr = src_buffer[offset_y]; /* Process the blocks that can be mirrored. */ for (dst_blk_x = 0; dst_blk_x < comp_width; dst_blk_x++) { dst_ptr = dst_row_ptr[dst_blk_x]; src_ptr = src_row_ptr[comp_width - dst_blk_x - 1]; for (i = 0; i < DCTSIZE2; i += 2) { *dst_ptr++ = *src_ptr++; *dst_ptr++ = - *src_ptr++; } } /* Any remaining right-edge blocks are only copied. */ for (; dst_blk_x < compptr->width_in_blocks; dst_blk_x++) { dst_ptr = dst_row_ptr[dst_blk_x]; src_ptr = src_row_ptr[dst_blk_x]; for (i = 0; i < DCTSIZE2; i++) *dst_ptr++ = *src_ptr++; } } } } } } LOCAL(void) do_transverse (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, jvirt_barray_ptr *src_coef_arrays, jvirt_barray_ptr *dst_coef_arrays) /* Transverse transpose is equivalent to * 1. 180 degree rotation; * 2. Transposition; * or * 1. Horizontal mirroring; * 2. Transposition; * 3. Horizontal mirroring. * These steps are merged into a single processing routine. */ { JDIMENSION MCU_cols, MCU_rows, comp_width, comp_height, dst_blk_x, dst_blk_y; int ci, i, j, offset_x, offset_y; JBLOCKARRAY src_buffer, dst_buffer; JCOEFPTR src_ptr, dst_ptr; jpeg_component_info *compptr; MCU_cols = dstinfo->image_width / (dstinfo->max_h_samp_factor * DCTSIZE); MCU_rows = dstinfo->image_height / (dstinfo->max_v_samp_factor * DCTSIZE); for (ci = 0; ci < dstinfo->num_components; ci++) { compptr = dstinfo->comp_info + ci; comp_width = MCU_cols * compptr->h_samp_factor; comp_height = MCU_rows * compptr->v_samp_factor; for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; dst_blk_y += compptr->v_samp_factor) { dst_buffer = (*srcinfo->mem->access_virt_barray) ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y, (JDIMENSION) compptr->v_samp_factor, TRUE); for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; dst_blk_x += compptr->h_samp_factor) { src_buffer = (*srcinfo->mem->access_virt_barray) ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_x, (JDIMENSION) compptr->h_samp_factor, FALSE); for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) { if (dst_blk_y < comp_height) { src_ptr = src_buffer[offset_x] [comp_height - dst_blk_y - offset_y - 1]; if (dst_blk_x < comp_width) { /* Block is within the mirrorable area. */ dst_ptr = dst_buffer[offset_y] [comp_width - dst_blk_x - offset_x - 1]; for (i = 0; i < DCTSIZE; i++) { for (j = 0; j < DCTSIZE; j++) { dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; j++; dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j]; } i++; for (j = 0; j < DCTSIZE; j++) { dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j]; j++; dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; } } } else { /* Right-edge blocks are mirrored in y only */ dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x]; for (i = 0; i < DCTSIZE; i++) { for (j = 0; j < DCTSIZE; j++) { dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; j++; dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j]; } } } } else { src_ptr = src_buffer[offset_x][dst_blk_y + offset_y]; if (dst_blk_x < comp_width) { /* Bottom-edge blocks are mirrored in x only */ dst_ptr = dst_buffer[offset_y] [comp_width - dst_blk_x - offset_x - 1]; for (i = 0; i < DCTSIZE; i++) { for (j = 0; j < DCTSIZE; j++) dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; i++; for (j = 0; j < DCTSIZE; j++) dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j]; } } else { /* At lower right corner, just transpose, no mirroring */ dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x]; for (i = 0; i < DCTSIZE; i++) for (j = 0; j < DCTSIZE; j++) dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; } } } } } } } } /* Request any required workspace. * * We allocate the workspace virtual arrays from the source decompression * object, so that all the arrays (both the original data and the workspace) * will be taken into account while making memory management decisions. * Hence, this routine must be called after jpeg_read_header (which reads * the image dimensions) and before jpeg_read_coefficients (which realizes * the source's virtual arrays). */ GLOBAL(void) jtransform_request_workspace (j_decompress_ptr srcinfo, jpeg_transform_info *info) { jvirt_barray_ptr *coef_arrays = NULL; jpeg_component_info *compptr; int ci; if (info->force_grayscale && srcinfo->jpeg_color_space == JCS_YCbCr && srcinfo->num_components == 3) { /* We'll only process the first component */ info->num_components = 1; } else { /* Process all the components */ info->num_components = srcinfo->num_components; } switch (info->transform) { case JXFORM_NONE: case JXFORM_FLIP_H: /* Don't need a workspace array */ break; case JXFORM_FLIP_V: case JXFORM_ROT_180: /* Need workspace arrays having same dimensions as source image. * Note that we allocate arrays padded out to the next iMCU boundary, * so that transform routines need not worry about missing edge blocks. */ coef_arrays = (jvirt_barray_ptr *) (*srcinfo->mem->alloc_small) ((j_common_ptr) srcinfo, JPOOL_IMAGE, SIZEOF(jvirt_barray_ptr) * info->num_components); for (ci = 0; ci < info->num_components; ci++) { compptr = srcinfo->comp_info + ci; coef_arrays[ci] = (*srcinfo->mem->request_virt_barray) ((j_common_ptr) srcinfo, JPOOL_IMAGE, FALSE, (JDIMENSION) jround_up((long) compptr->width_in_blocks, (long) compptr->h_samp_factor), (JDIMENSION) jround_up((long) compptr->height_in_blocks, (long) compptr->v_samp_factor), (JDIMENSION) compptr->v_samp_factor); } break; case JXFORM_TRANSPOSE: case JXFORM_TRANSVERSE: case JXFORM_ROT_90: case JXFORM_ROT_270: /* Need workspace arrays having transposed dimensions. * Note that we allocate arrays padded out to the next iMCU boundary, * so that transform routines need not worry about missing edge blocks. */ coef_arrays = (jvirt_barray_ptr *) (*srcinfo->mem->alloc_small) ((j_common_ptr) srcinfo, JPOOL_IMAGE, SIZEOF(jvirt_barray_ptr) * info->num_components); for (ci = 0; ci < info->num_components; ci++) { compptr = srcinfo->comp_info + ci; coef_arrays[ci] = (*srcinfo->mem->request_virt_barray) ((j_common_ptr) srcinfo, JPOOL_IMAGE, FALSE, (JDIMENSION) jround_up((long) compptr->height_in_blocks, (long) compptr->v_samp_factor), (JDIMENSION) jround_up((long) compptr->width_in_blocks, (long) compptr->h_samp_factor), (JDIMENSION) compptr->h_samp_factor); } break; } info->workspace_coef_arrays = coef_arrays; } /* Transpose destination image parameters */ LOCAL(void) transpose_critical_parameters (j_compress_ptr dstinfo) { int tblno, i, j, ci, itemp; jpeg_component_info *compptr; JQUANT_TBL *qtblptr; JDIMENSION dtemp; UINT16 qtemp; /* Transpose basic image dimensions */ dtemp = dstinfo->image_width; dstinfo->image_width = dstinfo->image_height; dstinfo->image_height = dtemp; /* Transpose sampling factors */ for (ci = 0; ci < dstinfo->num_components; ci++) { compptr = dstinfo->comp_info + ci; itemp = compptr->h_samp_factor; compptr->h_samp_factor = compptr->v_samp_factor; compptr->v_samp_factor = itemp; } /* Transpose quantization tables */ for (tblno = 0; tblno < NUM_QUANT_TBLS; tblno++) { qtblptr = dstinfo->quant_tbl_ptrs[tblno]; if (qtblptr != NULL) { for (i = 0; i < DCTSIZE; i++) { for (j = 0; j < i; j++) { qtemp = qtblptr->quantval[i*DCTSIZE+j]; qtblptr->quantval[i*DCTSIZE+j] = qtblptr->quantval[j*DCTSIZE+i]; qtblptr->quantval[j*DCTSIZE+i] = qtemp; } } } } } /* Trim off any partial iMCUs on the indicated destination edge */ LOCAL(void) trim_right_edge (j_compress_ptr dstinfo) { int ci, max_h_samp_factor; JDIMENSION MCU_cols; /* We have to compute max_h_samp_factor ourselves, * because it hasn't been set yet in the destination * (and we don't want to use the source's value). */ max_h_samp_factor = 1; for (ci = 0; ci < dstinfo->num_components; ci++) { int h_samp_factor = dstinfo->comp_info[ci].h_samp_factor; max_h_samp_factor = MAX(max_h_samp_factor, h_samp_factor); } MCU_cols = dstinfo->image_width / (max_h_samp_factor * DCTSIZE); if (MCU_cols > 0) /* can't trim to 0 pixels */ dstinfo->image_width = MCU_cols * (max_h_samp_factor * DCTSIZE); } LOCAL(void) trim_bottom_edge (j_compress_ptr dstinfo) { int ci, max_v_samp_factor; JDIMENSION MCU_rows; /* We have to compute max_v_samp_factor ourselves, * because it hasn't been set yet in the destination * (and we don't want to use the source's value). */ max_v_samp_factor = 1; for (ci = 0; ci < dstinfo->num_components; ci++) { int v_samp_factor = dstinfo->comp_info[ci].v_samp_factor; max_v_samp_factor = MAX(max_v_samp_factor, v_samp_factor); } MCU_rows = dstinfo->image_height / (max_v_samp_factor * DCTSIZE); if (MCU_rows > 0) /* can't trim to 0 pixels */ dstinfo->image_height = MCU_rows * (max_v_samp_factor * DCTSIZE); } /* Adjust output image parameters as needed. * * This must be called after jpeg_copy_critical_parameters() * and before jpeg_write_coefficients(). * * The return value is the set of virtual coefficient arrays to be written * (either the ones allocated by jtransform_request_workspace, or the * original source data arrays). The caller will need to pass this value * to jpeg_write_coefficients(). */ GLOBAL(jvirt_barray_ptr *) jtransform_adjust_parameters (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, jvirt_barray_ptr *src_coef_arrays, jpeg_transform_info *info) { /* If force-to-grayscale is requested, adjust destination parameters */ if (info->force_grayscale) { /* We use jpeg_set_colorspace to make sure subsidiary settings get fixed * properly. Among other things, the target h_samp_factor & v_samp_factor * will get set to 1, which typically won't match the source. * In fact we do this even if the source is already grayscale; that * provides an easy way of coercing a grayscale JPEG with funny sampling * factors to the customary 1,1. (Some decoders fail on other factors.) */ if ((dstinfo->jpeg_color_space == JCS_YCbCr && dstinfo->num_components == 3) || (dstinfo->jpeg_color_space == JCS_GRAYSCALE && dstinfo->num_components == 1)) { /* We have to preserve the source's quantization table number. */ int sv_quant_tbl_no = dstinfo->comp_info[0].quant_tbl_no; jpeg_set_colorspace(dstinfo, JCS_GRAYSCALE); dstinfo->comp_info[0].quant_tbl_no = sv_quant_tbl_no; } else { /* Sorry, can't do it */ ERREXIT(dstinfo, JERR_CONVERSION_NOTIMPL); } } /* Correct the destination's image dimensions etc if necessary */ switch (info->transform) { case JXFORM_NONE: /* Nothing to do */ break; case JXFORM_FLIP_H: if (info->trim) trim_right_edge(dstinfo); break; case JXFORM_FLIP_V: if (info->trim) trim_bottom_edge(dstinfo); break; case JXFORM_TRANSPOSE: transpose_critical_parameters(dstinfo); /* transpose does NOT have to trim anything */ break; case JXFORM_TRANSVERSE: transpose_critical_parameters(dstinfo); if (info->trim) { trim_right_edge(dstinfo); trim_bottom_edge(dstinfo); } break; case JXFORM_ROT_90: transpose_critical_parameters(dstinfo); if (info->trim) trim_right_edge(dstinfo); break; case JXFORM_ROT_180: if (info->trim) { trim_right_edge(dstinfo); trim_bottom_edge(dstinfo); } break; case JXFORM_ROT_270: transpose_critical_parameters(dstinfo); if (info->trim) trim_bottom_edge(dstinfo); break; } /* Return the appropriate output data set */ if (info->workspace_coef_arrays != NULL) return info->workspace_coef_arrays; return src_coef_arrays; } /* Execute the actual transformation, if any. * * This must be called *after* jpeg_write_coefficients, because it depends * on jpeg_write_coefficients to have computed subsidiary values such as * the per-component width and height fields in the destination object. * * Note that some transformations will modify the source data arrays! */ GLOBAL(void) jtransform_execute_transformation (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, jvirt_barray_ptr *src_coef_arrays, jpeg_transform_info *info) { jvirt_barray_ptr *dst_coef_arrays = info->workspace_coef_arrays; switch (info->transform) { case JXFORM_NONE: break; case JXFORM_FLIP_H: do_flip_h(srcinfo, dstinfo, src_coef_arrays); break; case JXFORM_FLIP_V: do_flip_v(srcinfo, dstinfo, src_coef_arrays, dst_coef_arrays); break; case JXFORM_TRANSPOSE: do_transpose(srcinfo, dstinfo, src_coef_arrays, dst_coef_arrays); break; case JXFORM_TRANSVERSE: do_transverse(srcinfo, dstinfo, src_coef_arrays, dst_coef_arrays); break; case JXFORM_ROT_90: do_rot_90(srcinfo, dstinfo, src_coef_arrays, dst_coef_arrays); break; case JXFORM_ROT_180: do_rot_180(srcinfo, dstinfo, src_coef_arrays, dst_coef_arrays); break; case JXFORM_ROT_270: do_rot_270(srcinfo, dstinfo, src_coef_arrays, dst_coef_arrays); break; } } #endif /* TRANSFORMS_SUPPORTED */ /* Setup decompression object to save desired markers in memory. * This must be called before jpeg_read_header() to have the desired effect. */ GLOBAL(void) jcopy_markers_setup (j_decompress_ptr srcinfo, JCOPY_OPTION option) { #ifdef SAVE_MARKERS_SUPPORTED int m; /* Save comments except under NONE option */ if (option != JCOPYOPT_NONE) { jpeg_save_markers(srcinfo, JPEG_COM, 0xFFFF); } /* Save all types of APPn markers iff ALL option */ if (option == JCOPYOPT_ALL) { for (m = 0; m < 16; m++) jpeg_save_markers(srcinfo, JPEG_APP0 + m, 0xFFFF); } #endif /* SAVE_MARKERS_SUPPORTED */ } /* Copy markers saved in the given source object to the destination object. * This should be called just after jpeg_start_compress() or * jpeg_write_coefficients(). * Note that those routines will have written the SOI, and also the * JFIF APP0 or Adobe APP14 markers if selected. */ GLOBAL(void) jcopy_markers_execute (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, JCOPY_OPTION option) { jpeg_saved_marker_ptr marker; /* In the current implementation, we don't actually need to examine the * option flag here; we just copy everything that got saved. * But to avoid confusion, we do not output JFIF and Adobe APP14 markers * if the encoder library already wrote one. */ for (marker = srcinfo->marker_list; marker != NULL; marker = marker->next) { if (dstinfo->write_JFIF_header && marker->marker == JPEG_APP0 && marker->data_length >= 5 && GETJOCTET(marker->data[0]) == 0x4A && GETJOCTET(marker->data[1]) == 0x46 && GETJOCTET(marker->data[2]) == 0x49 && GETJOCTET(marker->data[3]) == 0x46 && GETJOCTET(marker->data[4]) == 0) continue; /* reject duplicate JFIF */ if (dstinfo->write_Adobe_marker && marker->marker == JPEG_APP0+14 && marker->data_length >= 5 && GETJOCTET(marker->data[0]) == 0x41 && GETJOCTET(marker->data[1]) == 0x64 && GETJOCTET(marker->data[2]) == 0x6F && GETJOCTET(marker->data[3]) == 0x62 && GETJOCTET(marker->data[4]) == 0x65) continue; /* reject duplicate Adobe */ #ifdef NEED_FAR_POINTERS /* We could use jpeg_write_marker if the data weren't FAR... */ { unsigned int i; jpeg_write_m_header(dstinfo, marker->marker, marker->data_length); for (i = 0; i < marker->data_length; i++) jpeg_write_m_byte(dstinfo, marker->data[i]); } #else jpeg_write_marker(dstinfo, marker->marker, marker->data, marker->data_length); #endif } } fbi-2.10/jpeg/62/jpeglib.h0000644000175000017500000013217512506525033013277 0ustar jmmjmm/* * jpeglib.h * * Copyright (C) 1991-1998, Thomas G. Lane. * This file is part of the Independent JPEG Group's software. * For conditions of distribution and use, see the accompanying README file. * * This file defines the application interface for the JPEG library. * Most applications using the library need only include this file, * and perhaps jerror.h if they want to know the exact error codes. */ #ifndef JPEGLIB_H #define JPEGLIB_H /* * First we include the configuration files that record how this * installation of the JPEG library is set up. jconfig.h can be * generated automatically for many systems. jmorecfg.h contains * manual configuration options that most people need not worry about. */ #ifndef JCONFIG_INCLUDED /* in case jinclude.h already did */ #include "jconfig.h" /* widely used configuration options */ #endif #include "jmorecfg.h" /* seldom changed options */ /* Version ID for the JPEG library. * Might be useful for tests like "#if JPEG_LIB_VERSION >= 60". */ #define JPEG_LIB_VERSION 62 /* Version 6b */ /* Various constants determining the sizes of things. * All of these are specified by the JPEG standard, so don't change them * if you want to be compatible. */ #define DCTSIZE 8 /* The basic DCT block is 8x8 samples */ #define DCTSIZE2 64 /* DCTSIZE squared; # of elements in a block */ #define NUM_QUANT_TBLS 4 /* Quantization tables are numbered 0..3 */ #define NUM_HUFF_TBLS 4 /* Huffman tables are numbered 0..3 */ #define NUM_ARITH_TBLS 16 /* Arith-coding tables are numbered 0..15 */ #define MAX_COMPS_IN_SCAN 4 /* JPEG limit on # of components in one scan */ #define MAX_SAMP_FACTOR 4 /* JPEG limit on sampling factors */ /* Unfortunately, some bozo at Adobe saw no reason to be bound by the standard; * the PostScript DCT filter can emit files with many more than 10 blocks/MCU. * If you happen to run across such a file, you can up D_MAX_BLOCKS_IN_MCU * to handle it. We even let you do this from the jconfig.h file. However, * we strongly discourage changing C_MAX_BLOCKS_IN_MCU; just because Adobe * sometimes emits noncompliant files doesn't mean you should too. */ #define C_MAX_BLOCKS_IN_MCU 10 /* compressor's limit on blocks per MCU */ #ifndef D_MAX_BLOCKS_IN_MCU #define D_MAX_BLOCKS_IN_MCU 10 /* decompressor's limit on blocks per MCU */ #endif /* Data structures for images (arrays of samples and of DCT coefficients). * On 80x86 machines, the image arrays are too big for near pointers, * but the pointer arrays can fit in near memory. */ typedef JSAMPLE FAR *JSAMPROW; /* ptr to one image row of pixel samples. */ typedef JSAMPROW *JSAMPARRAY; /* ptr to some rows (a 2-D sample array) */ typedef JSAMPARRAY *JSAMPIMAGE; /* a 3-D sample array: top index is color */ typedef JCOEF JBLOCK[DCTSIZE2]; /* one block of coefficients */ typedef JBLOCK FAR *JBLOCKROW; /* pointer to one row of coefficient blocks */ typedef JBLOCKROW *JBLOCKARRAY; /* a 2-D array of coefficient blocks */ typedef JBLOCKARRAY *JBLOCKIMAGE; /* a 3-D array of coefficient blocks */ typedef JCOEF FAR *JCOEFPTR; /* useful in a couple of places */ /* Types for JPEG compression parameters and working tables. */ /* DCT coefficient quantization tables. */ typedef struct { /* This array gives the coefficient quantizers in natural array order * (not the zigzag order in which they are stored in a JPEG DQT marker). * CAUTION: IJG versions prior to v6a kept this array in zigzag order. */ UINT16 quantval[DCTSIZE2]; /* quantization step for each coefficient */ /* This field is used only during compression. It's initialized FALSE when * the table is created, and set TRUE when it's been output to the file. * You could suppress output of a table by setting this to TRUE. * (See jpeg_suppress_tables for an example.) */ boolean sent_table; /* TRUE when table has been output */ } JQUANT_TBL; /* Huffman coding tables. */ typedef struct { /* These two fields directly represent the contents of a JPEG DHT marker */ UINT8 bits[17]; /* bits[k] = # of symbols with codes of */ /* length k bits; bits[0] is unused */ UINT8 huffval[256]; /* The symbols, in order of incr code length */ /* This field is used only during compression. It's initialized FALSE when * the table is created, and set TRUE when it's been output to the file. * You could suppress output of a table by setting this to TRUE. * (See jpeg_suppress_tables for an example.) */ boolean sent_table; /* TRUE when table has been output */ } JHUFF_TBL; /* Basic info about one component (color channel). */ typedef struct { /* These values are fixed over the whole image. */ /* For compression, they must be supplied by parameter setup; */ /* for decompression, they are read from the SOF marker. */ int component_id; /* identifier for this component (0..255) */ int component_index; /* its index in SOF or cinfo->comp_info[] */ int h_samp_factor; /* horizontal sampling factor (1..4) */ int v_samp_factor; /* vertical sampling factor (1..4) */ int quant_tbl_no; /* quantization table selector (0..3) */ /* These values may vary between scans. */ /* For compression, they must be supplied by parameter setup; */ /* for decompression, they are read from the SOS marker. */ /* The decompressor output side may not use these variables. */ int dc_tbl_no; /* DC entropy table selector (0..3) */ int ac_tbl_no; /* AC entropy table selector (0..3) */ /* Remaining fields should be treated as private by applications. */ /* These values are computed during compression or decompression startup: */ /* Component's size in DCT blocks. * Any dummy blocks added to complete an MCU are not counted; therefore * these values do not depend on whether a scan is interleaved or not. */ JDIMENSION width_in_blocks; JDIMENSION height_in_blocks; /* Size of a DCT block in samples. Always DCTSIZE for compression. * For decompression this is the size of the output from one DCT block, * reflecting any scaling we choose to apply during the IDCT step. * Values of 1,2,4,8 are likely to be supported. Note that different * components may receive different IDCT scalings. */ int DCT_scaled_size; /* The downsampled dimensions are the component's actual, unpadded number * of samples at the main buffer (preprocessing/compression interface), thus * downsampled_width = ceil(image_width * Hi/Hmax) * and similarly for height. For decompression, IDCT scaling is included, so * downsampled_width = ceil(image_width * Hi/Hmax * DCT_scaled_size/DCTSIZE) */ JDIMENSION downsampled_width; /* actual width in samples */ JDIMENSION downsampled_height; /* actual height in samples */ /* This flag is used only for decompression. In cases where some of the * components will be ignored (eg grayscale output from YCbCr image), * we can skip most computations for the unused components. */ boolean component_needed; /* do we need the value of this component? */ /* These values are computed before starting a scan of the component. */ /* The decompressor output side may not use these variables. */ int MCU_width; /* number of blocks per MCU, horizontally */ int MCU_height; /* number of blocks per MCU, vertically */ int MCU_blocks; /* MCU_width * MCU_height */ int MCU_sample_width; /* MCU width in samples, MCU_width*DCT_scaled_size */ int last_col_width; /* # of non-dummy blocks across in last MCU */ int last_row_height; /* # of non-dummy blocks down in last MCU */ /* Saved quantization table for component; NULL if none yet saved. * See jdinput.c comments about the need for this information. * This field is currently used only for decompression. */ JQUANT_TBL * quant_table; /* Private per-component storage for DCT or IDCT subsystem. */ void * dct_table; } jpeg_component_info; /* The script for encoding a multiple-scan file is an array of these: */ typedef struct { int comps_in_scan; /* number of components encoded in this scan */ int component_index[MAX_COMPS_IN_SCAN]; /* their SOF/comp_info[] indexes */ int Ss, Se; /* progressive JPEG spectral selection parms */ int Ah, Al; /* progressive JPEG successive approx. parms */ } jpeg_scan_info; /* The decompressor can save APPn and COM markers in a list of these: */ typedef struct jpeg_marker_struct FAR * jpeg_saved_marker_ptr; struct jpeg_marker_struct { jpeg_saved_marker_ptr next; /* next in list, or NULL */ UINT8 marker; /* marker code: JPEG_COM, or JPEG_APP0+n */ unsigned int original_length; /* # bytes of data in the file */ unsigned int data_length; /* # bytes of data saved at data[] */ JOCTET FAR * data; /* the data contained in the marker */ /* the marker length word is not counted in data_length or original_length */ }; /* Known color spaces. */ typedef enum { JCS_UNKNOWN, /* error/unspecified */ JCS_GRAYSCALE, /* monochrome */ JCS_RGB, /* red/green/blue */ JCS_YCbCr, /* Y/Cb/Cr (also known as YUV) */ JCS_CMYK, /* C/M/Y/K */ JCS_YCCK /* Y/Cb/Cr/K */ } J_COLOR_SPACE; /* DCT/IDCT algorithm options. */ typedef enum { JDCT_ISLOW, /* slow but accurate integer algorithm */ JDCT_IFAST, /* faster, less accurate integer method */ JDCT_FLOAT /* floating-point: accurate, fast on fast HW */ } J_DCT_METHOD; #ifndef JDCT_DEFAULT /* may be overridden in jconfig.h */ #define JDCT_DEFAULT JDCT_ISLOW #endif #ifndef JDCT_FASTEST /* may be overridden in jconfig.h */ #define JDCT_FASTEST JDCT_IFAST #endif /* Dithering options for decompression. */ typedef enum { JDITHER_NONE, /* no dithering */ JDITHER_ORDERED, /* simple ordered dither */ JDITHER_FS /* Floyd-Steinberg error diffusion dither */ } J_DITHER_MODE; /* Common fields between JPEG compression and decompression master structs. */ #define jpeg_common_fields \ struct jpeg_error_mgr * err; /* Error handler module */\ struct jpeg_memory_mgr * mem; /* Memory manager module */\ struct jpeg_progress_mgr * progress; /* Progress monitor, or NULL if none */\ void * client_data; /* Available for use by application */\ boolean is_decompressor; /* So common code can tell which is which */\ int global_state /* For checking call sequence validity */ /* Routines that are to be used by both halves of the library are declared * to receive a pointer to this structure. There are no actual instances of * jpeg_common_struct, only of jpeg_compress_struct and jpeg_decompress_struct. */ struct jpeg_common_struct { jpeg_common_fields; /* Fields common to both master struct types */ /* Additional fields follow in an actual jpeg_compress_struct or * jpeg_decompress_struct. All three structs must agree on these * initial fields! (This would be a lot cleaner in C++.) */ }; typedef struct jpeg_common_struct * j_common_ptr; typedef struct jpeg_compress_struct * j_compress_ptr; typedef struct jpeg_decompress_struct * j_decompress_ptr; /* Master record for a compression instance */ struct jpeg_compress_struct { jpeg_common_fields; /* Fields shared with jpeg_decompress_struct */ /* Destination for compressed data */ struct jpeg_destination_mgr * dest; /* Description of source image --- these fields must be filled in by * outer application before starting compression. in_color_space must * be correct before you can even call jpeg_set_defaults(). */ JDIMENSION image_width; /* input image width */ JDIMENSION image_height; /* input image height */ int input_components; /* # of color components in input image */ J_COLOR_SPACE in_color_space; /* colorspace of input image */ double input_gamma; /* image gamma of input image */ /* Compression parameters --- these fields must be set before calling * jpeg_start_compress(). We recommend calling jpeg_set_defaults() to * initialize everything to reasonable defaults, then changing anything * the application specifically wants to change. That way you won't get * burnt when new parameters are added. Also note that there are several * helper routines to simplify changing parameters. */ int data_precision; /* bits of precision in image data */ int num_components; /* # of color components in JPEG image */ J_COLOR_SPACE jpeg_color_space; /* colorspace of JPEG image */ jpeg_component_info * comp_info; /* comp_info[i] describes component that appears i'th in SOF */ JQUANT_TBL * quant_tbl_ptrs[NUM_QUANT_TBLS]; /* ptrs to coefficient quantization tables, or NULL if not defined */ JHUFF_TBL * dc_huff_tbl_ptrs[NUM_HUFF_TBLS]; JHUFF_TBL * ac_huff_tbl_ptrs[NUM_HUFF_TBLS]; /* ptrs to Huffman coding tables, or NULL if not defined */ UINT8 arith_dc_L[NUM_ARITH_TBLS]; /* L values for DC arith-coding tables */ UINT8 arith_dc_U[NUM_ARITH_TBLS]; /* U values for DC arith-coding tables */ UINT8 arith_ac_K[NUM_ARITH_TBLS]; /* Kx values for AC arith-coding tables */ int num_scans; /* # of entries in scan_info array */ const jpeg_scan_info * scan_info; /* script for multi-scan file, or NULL */ /* The default value of scan_info is NULL, which causes a single-scan * sequential JPEG file to be emitted. To create a multi-scan file, * set num_scans and scan_info to point to an array of scan definitions. */ boolean raw_data_in; /* TRUE=caller supplies downsampled data */ boolean arith_code; /* TRUE=arithmetic coding, FALSE=Huffman */ boolean optimize_coding; /* TRUE=optimize entropy encoding parms */ boolean CCIR601_sampling; /* TRUE=first samples are cosited */ int smoothing_factor; /* 1..100, or 0 for no input smoothing */ J_DCT_METHOD dct_method; /* DCT algorithm selector */ /* The restart interval can be specified in absolute MCUs by setting * restart_interval, or in MCU rows by setting restart_in_rows * (in which case the correct restart_interval will be figured * for each scan). */ unsigned int restart_interval; /* MCUs per restart, or 0 for no restart */ int restart_in_rows; /* if > 0, MCU rows per restart interval */ /* Parameters controlling emission of special markers. */ boolean write_JFIF_header; /* should a JFIF marker be written? */ UINT8 JFIF_major_version; /* What to write for the JFIF version number */ UINT8 JFIF_minor_version; /* These three values are not used by the JPEG code, merely copied */ /* into the JFIF APP0 marker. density_unit can be 0 for unknown, */ /* 1 for dots/inch, or 2 for dots/cm. Note that the pixel aspect */ /* ratio is defined by X_density/Y_density even when density_unit=0. */ UINT8 density_unit; /* JFIF code for pixel size units */ UINT16 X_density; /* Horizontal pixel density */ UINT16 Y_density; /* Vertical pixel density */ boolean write_Adobe_marker; /* should an Adobe marker be written? */ /* State variable: index of next scanline to be written to * jpeg_write_scanlines(). Application may use this to control its * processing loop, e.g., "while (next_scanline < image_height)". */ JDIMENSION next_scanline; /* 0 .. image_height-1 */ /* Remaining fields are known throughout compressor, but generally * should not be touched by a surrounding application. */ /* * These fields are computed during compression startup */ boolean progressive_mode; /* TRUE if scan script uses progressive mode */ int max_h_samp_factor; /* largest h_samp_factor */ int max_v_samp_factor; /* largest v_samp_factor */ JDIMENSION total_iMCU_rows; /* # of iMCU rows to be input to coef ctlr */ /* The coefficient controller receives data in units of MCU rows as defined * for fully interleaved scans (whether the JPEG file is interleaved or not). * There are v_samp_factor * DCTSIZE sample rows of each component in an * "iMCU" (interleaved MCU) row. */ /* * These fields are valid during any one scan. * They describe the components and MCUs actually appearing in the scan. */ int comps_in_scan; /* # of JPEG components in this scan */ jpeg_component_info * cur_comp_info[MAX_COMPS_IN_SCAN]; /* *cur_comp_info[i] describes component that appears i'th in SOS */ JDIMENSION MCUs_per_row; /* # of MCUs across the image */ JDIMENSION MCU_rows_in_scan; /* # of MCU rows in the image */ int blocks_in_MCU; /* # of DCT blocks per MCU */ int MCU_membership[C_MAX_BLOCKS_IN_MCU]; /* MCU_membership[i] is index in cur_comp_info of component owning */ /* i'th block in an MCU */ int Ss, Se, Ah, Al; /* progressive JPEG parameters for scan */ /* * Links to compression subobjects (methods and private variables of modules) */ struct jpeg_comp_master * master; struct jpeg_c_main_controller * main; struct jpeg_c_prep_controller * prep; struct jpeg_c_coef_controller * coef; struct jpeg_marker_writer * marker; struct jpeg_color_converter * cconvert; struct jpeg_downsampler * downsample; struct jpeg_forward_dct * fdct; struct jpeg_entropy_encoder * entropy; jpeg_scan_info * script_space; /* workspace for jpeg_simple_progression */ int script_space_size; }; /* Master record for a decompression instance */ struct jpeg_decompress_struct { jpeg_common_fields; /* Fields shared with jpeg_compress_struct */ /* Source of compressed data */ struct jpeg_source_mgr * src; /* Basic description of image --- filled in by jpeg_read_header(). */ /* Application may inspect these values to decide how to process image. */ JDIMENSION image_width; /* nominal image width (from SOF marker) */ JDIMENSION image_height; /* nominal image height */ int num_components; /* # of color components in JPEG image */ J_COLOR_SPACE jpeg_color_space; /* colorspace of JPEG image */ /* Decompression processing parameters --- these fields must be set before * calling jpeg_start_decompress(). Note that jpeg_read_header() initializes * them to default values. */ J_COLOR_SPACE out_color_space; /* colorspace for output */ unsigned int scale_num, scale_denom; /* fraction by which to scale image */ double output_gamma; /* image gamma wanted in output */ boolean buffered_image; /* TRUE=multiple output passes */ boolean raw_data_out; /* TRUE=downsampled data wanted */ J_DCT_METHOD dct_method; /* IDCT algorithm selector */ boolean do_fancy_upsampling; /* TRUE=apply fancy upsampling */ boolean do_block_smoothing; /* TRUE=apply interblock smoothing */ boolean quantize_colors; /* TRUE=colormapped output wanted */ /* the following are ignored if not quantize_colors: */ J_DITHER_MODE dither_mode; /* type of color dithering to use */ boolean two_pass_quantize; /* TRUE=use two-pass color quantization */ int desired_number_of_colors; /* max # colors to use in created colormap */ /* these are significant only in buffered-image mode: */ boolean enable_1pass_quant; /* enable future use of 1-pass quantizer */ boolean enable_external_quant;/* enable future use of external colormap */ boolean enable_2pass_quant; /* enable future use of 2-pass quantizer */ /* Description of actual output image that will be returned to application. * These fields are computed by jpeg_start_decompress(). * You can also use jpeg_calc_output_dimensions() to determine these values * in advance of calling jpeg_start_decompress(). */ JDIMENSION output_width; /* scaled image width */ JDIMENSION output_height; /* scaled image height */ int out_color_components; /* # of color components in out_color_space */ int output_components; /* # of color components returned */ /* output_components is 1 (a colormap index) when quantizing colors; * otherwise it equals out_color_components. */ int rec_outbuf_height; /* min recommended height of scanline buffer */ /* If the buffer passed to jpeg_read_scanlines() is less than this many rows * high, space and time will be wasted due to unnecessary data copying. * Usually rec_outbuf_height will be 1 or 2, at most 4. */ /* When quantizing colors, the output colormap is described by these fields. * The application can supply a colormap by setting colormap non-NULL before * calling jpeg_start_decompress; otherwise a colormap is created during * jpeg_start_decompress or jpeg_start_output. * The map has out_color_components rows and actual_number_of_colors columns. */ int actual_number_of_colors; /* number of entries in use */ JSAMPARRAY colormap; /* The color map as a 2-D pixel array */ /* State variables: these variables indicate the progress of decompression. * The application may examine these but must not modify them. */ /* Row index of next scanline to be read from jpeg_read_scanlines(). * Application may use this to control its processing loop, e.g., * "while (output_scanline < output_height)". */ JDIMENSION output_scanline; /* 0 .. output_height-1 */ /* Current input scan number and number of iMCU rows completed in scan. * These indicate the progress of the decompressor input side. */ int input_scan_number; /* Number of SOS markers seen so far */ JDIMENSION input_iMCU_row; /* Number of iMCU rows completed */ /* The "output scan number" is the notional scan being displayed by the * output side. The decompressor will not allow output scan/row number * to get ahead of input scan/row, but it can fall arbitrarily far behind. */ int output_scan_number; /* Nominal scan number being displayed */ JDIMENSION output_iMCU_row; /* Number of iMCU rows read */ /* Current progression status. coef_bits[c][i] indicates the precision * with which component c's DCT coefficient i (in zigzag order) is known. * It is -1 when no data has yet been received, otherwise it is the point * transform (shift) value for the most recent scan of the coefficient * (thus, 0 at completion of the progression). * This pointer is NULL when reading a non-progressive file. */ int (*coef_bits)[DCTSIZE2]; /* -1 or current Al value for each coef */ /* Internal JPEG parameters --- the application usually need not look at * these fields. Note that the decompressor output side may not use * any parameters that can change between scans. */ /* Quantization and Huffman tables are carried forward across input * datastreams when processing abbreviated JPEG datastreams. */ JQUANT_TBL * quant_tbl_ptrs[NUM_QUANT_TBLS]; /* ptrs to coefficient quantization tables, or NULL if not defined */ JHUFF_TBL * dc_huff_tbl_ptrs[NUM_HUFF_TBLS]; JHUFF_TBL * ac_huff_tbl_ptrs[NUM_HUFF_TBLS]; /* ptrs to Huffman coding tables, or NULL if not defined */ /* These parameters are never carried across datastreams, since they * are given in SOF/SOS markers or defined to be reset by SOI. */ int data_precision; /* bits of precision in image data */ jpeg_component_info * comp_info; /* comp_info[i] describes component that appears i'th in SOF */ boolean progressive_mode; /* TRUE if SOFn specifies progressive mode */ boolean arith_code; /* TRUE=arithmetic coding, FALSE=Huffman */ UINT8 arith_dc_L[NUM_ARITH_TBLS]; /* L values for DC arith-coding tables */ UINT8 arith_dc_U[NUM_ARITH_TBLS]; /* U values for DC arith-coding tables */ UINT8 arith_ac_K[NUM_ARITH_TBLS]; /* Kx values for AC arith-coding tables */ unsigned int restart_interval; /* MCUs per restart interval, or 0 for no restart */ /* These fields record data obtained from optional markers recognized by * the JPEG library. */ boolean saw_JFIF_marker; /* TRUE iff a JFIF APP0 marker was found */ /* Data copied from JFIF marker; only valid if saw_JFIF_marker is TRUE: */ UINT8 JFIF_major_version; /* JFIF version number */ UINT8 JFIF_minor_version; UINT8 density_unit; /* JFIF code for pixel size units */ UINT16 X_density; /* Horizontal pixel density */ UINT16 Y_density; /* Vertical pixel density */ boolean saw_Adobe_marker; /* TRUE iff an Adobe APP14 marker was found */ UINT8 Adobe_transform; /* Color transform code from Adobe marker */ boolean CCIR601_sampling; /* TRUE=first samples are cosited */ /* Aside from the specific data retained from APPn markers known to the * library, the uninterpreted contents of any or all APPn and COM markers * can be saved in a list for examination by the application. */ jpeg_saved_marker_ptr marker_list; /* Head of list of saved markers */ /* Remaining fields are known throughout decompressor, but generally * should not be touched by a surrounding application. */ /* * These fields are computed during decompression startup */ int max_h_samp_factor; /* largest h_samp_factor */ int max_v_samp_factor; /* largest v_samp_factor */ int min_DCT_scaled_size; /* smallest DCT_scaled_size of any component */ JDIMENSION total_iMCU_rows; /* # of iMCU rows in image */ /* The coefficient controller's input and output progress is measured in * units of "iMCU" (interleaved MCU) rows. These are the same as MCU rows * in fully interleaved JPEG scans, but are used whether the scan is * interleaved or not. We define an iMCU row as v_samp_factor DCT block * rows of each component. Therefore, the IDCT output contains * v_samp_factor*DCT_scaled_size sample rows of a component per iMCU row. */ JSAMPLE * sample_range_limit; /* table for fast range-limiting */ /* * These fields are valid during any one scan. * They describe the components and MCUs actually appearing in the scan. * Note that the decompressor output side must not use these fields. */ int comps_in_scan; /* # of JPEG components in this scan */ jpeg_component_info * cur_comp_info[MAX_COMPS_IN_SCAN]; /* *cur_comp_info[i] describes component that appears i'th in SOS */ JDIMENSION MCUs_per_row; /* # of MCUs across the image */ JDIMENSION MCU_rows_in_scan; /* # of MCU rows in the image */ int blocks_in_MCU; /* # of DCT blocks per MCU */ int MCU_membership[D_MAX_BLOCKS_IN_MCU]; /* MCU_membership[i] is index in cur_comp_info of component owning */ /* i'th block in an MCU */ int Ss, Se, Ah, Al; /* progressive JPEG parameters for scan */ /* This field is shared between entropy decoder and marker parser. * It is either zero or the code of a JPEG marker that has been * read from the data source, but has not yet been processed. */ int unread_marker; /* * Links to decompression subobjects (methods, private variables of modules) */ struct jpeg_decomp_master * master; struct jpeg_d_main_controller * main; struct jpeg_d_coef_controller * coef; struct jpeg_d_post_controller * post; struct jpeg_input_controller * inputctl; struct jpeg_marker_reader * marker; struct jpeg_entropy_decoder * entropy; struct jpeg_inverse_dct * idct; struct jpeg_upsampler * upsample; struct jpeg_color_deconverter * cconvert; struct jpeg_color_quantizer * cquantize; }; /* "Object" declarations for JPEG modules that may be supplied or called * directly by the surrounding application. * As with all objects in the JPEG library, these structs only define the * publicly visible methods and state variables of a module. Additional * private fields may exist after the public ones. */ /* Error handler object */ struct jpeg_error_mgr { /* Error exit handler: does not return to caller */ JMETHOD(void, error_exit, (j_common_ptr cinfo)); /* Conditionally emit a trace or warning message */ JMETHOD(void, emit_message, (j_common_ptr cinfo, int msg_level)); /* Routine that actually outputs a trace or error message */ JMETHOD(void, output_message, (j_common_ptr cinfo)); /* Format a message string for the most recent JPEG error or message */ JMETHOD(void, format_message, (j_common_ptr cinfo, char * buffer)); #define JMSG_LENGTH_MAX 200 /* recommended size of format_message buffer */ /* Reset error state variables at start of a new image */ JMETHOD(void, reset_error_mgr, (j_common_ptr cinfo)); /* The message ID code and any parameters are saved here. * A message can have one string parameter or up to 8 int parameters. */ int msg_code; #define JMSG_STR_PARM_MAX 80 union { int i[8]; char s[JMSG_STR_PARM_MAX]; } msg_parm; /* Standard state variables for error facility */ int trace_level; /* max msg_level that will be displayed */ /* For recoverable corrupt-data errors, we emit a warning message, * but keep going unless emit_message chooses to abort. emit_message * should count warnings in num_warnings. The surrounding application * can check for bad data by seeing if num_warnings is nonzero at the * end of processing. */ long num_warnings; /* number of corrupt-data warnings */ /* These fields point to the table(s) of error message strings. * An application can change the table pointer to switch to a different * message list (typically, to change the language in which errors are * reported). Some applications may wish to add additional error codes * that will be handled by the JPEG library error mechanism; the second * table pointer is used for this purpose. * * First table includes all errors generated by JPEG library itself. * Error code 0 is reserved for a "no such error string" message. */ const char * const * jpeg_message_table; /* Library errors */ int last_jpeg_message; /* Table contains strings 0..last_jpeg_message */ /* Second table can be added by application (see cjpeg/djpeg for example). * It contains strings numbered first_addon_message..last_addon_message. */ const char * const * addon_message_table; /* Non-library errors */ int first_addon_message; /* code for first string in addon table */ int last_addon_message; /* code for last string in addon table */ }; /* Progress monitor object */ struct jpeg_progress_mgr { JMETHOD(void, progress_monitor, (j_common_ptr cinfo)); long pass_counter; /* work units completed in this pass */ long pass_limit; /* total number of work units in this pass */ int completed_passes; /* passes completed so far */ int total_passes; /* total number of passes expected */ }; /* Data destination object for compression */ struct jpeg_destination_mgr { JOCTET * next_output_byte; /* => next byte to write in buffer */ size_t free_in_buffer; /* # of byte spaces remaining in buffer */ JMETHOD(void, init_destination, (j_compress_ptr cinfo)); JMETHOD(boolean, empty_output_buffer, (j_compress_ptr cinfo)); JMETHOD(void, term_destination, (j_compress_ptr cinfo)); }; /* Data source object for decompression */ struct jpeg_source_mgr { const JOCTET * next_input_byte; /* => next byte to read from buffer */ size_t bytes_in_buffer; /* # of bytes remaining in buffer */ JMETHOD(void, init_source, (j_decompress_ptr cinfo)); JMETHOD(boolean, fill_input_buffer, (j_decompress_ptr cinfo)); JMETHOD(void, skip_input_data, (j_decompress_ptr cinfo, long num_bytes)); JMETHOD(boolean, resync_to_restart, (j_decompress_ptr cinfo, int desired)); JMETHOD(void, term_source, (j_decompress_ptr cinfo)); }; /* Memory manager object. * Allocates "small" objects (a few K total), "large" objects (tens of K), * and "really big" objects (virtual arrays with backing store if needed). * The memory manager does not allow individual objects to be freed; rather, * each created object is assigned to a pool, and whole pools can be freed * at once. This is faster and more convenient than remembering exactly what * to free, especially where malloc()/free() are not too speedy. * NB: alloc routines never return NULL. They exit to error_exit if not * successful. */ #define JPOOL_PERMANENT 0 /* lasts until master record is destroyed */ #define JPOOL_IMAGE 1 /* lasts until done with image/datastream */ #define JPOOL_NUMPOOLS 2 typedef struct jvirt_sarray_control * jvirt_sarray_ptr; typedef struct jvirt_barray_control * jvirt_barray_ptr; struct jpeg_memory_mgr { /* Method pointers */ JMETHOD(void *, alloc_small, (j_common_ptr cinfo, int pool_id, size_t sizeofobject)); JMETHOD(void FAR *, alloc_large, (j_common_ptr cinfo, int pool_id, size_t sizeofobject)); JMETHOD(JSAMPARRAY, alloc_sarray, (j_common_ptr cinfo, int pool_id, JDIMENSION samplesperrow, JDIMENSION numrows)); JMETHOD(JBLOCKARRAY, alloc_barray, (j_common_ptr cinfo, int pool_id, JDIMENSION blocksperrow, JDIMENSION numrows)); JMETHOD(jvirt_sarray_ptr, request_virt_sarray, (j_common_ptr cinfo, int pool_id, boolean pre_zero, JDIMENSION samplesperrow, JDIMENSION numrows, JDIMENSION maxaccess)); JMETHOD(jvirt_barray_ptr, request_virt_barray, (j_common_ptr cinfo, int pool_id, boolean pre_zero, JDIMENSION blocksperrow, JDIMENSION numrows, JDIMENSION maxaccess)); JMETHOD(void, realize_virt_arrays, (j_common_ptr cinfo)); JMETHOD(JSAMPARRAY, access_virt_sarray, (j_common_ptr cinfo, jvirt_sarray_ptr ptr, JDIMENSION start_row, JDIMENSION num_rows, boolean writable)); JMETHOD(JBLOCKARRAY, access_virt_barray, (j_common_ptr cinfo, jvirt_barray_ptr ptr, JDIMENSION start_row, JDIMENSION num_rows, boolean writable)); JMETHOD(void, free_pool, (j_common_ptr cinfo, int pool_id)); JMETHOD(void, self_destruct, (j_common_ptr cinfo)); /* Limit on memory allocation for this JPEG object. (Note that this is * merely advisory, not a guaranteed maximum; it only affects the space * used for virtual-array buffers.) May be changed by outer application * after creating the JPEG object. */ long max_memory_to_use; /* Maximum allocation request accepted by alloc_large. */ long max_alloc_chunk; }; /* Routine signature for application-supplied marker processing methods. * Need not pass marker code since it is stored in cinfo->unread_marker. */ typedef JMETHOD(boolean, jpeg_marker_parser_method, (j_decompress_ptr cinfo)); /* Declarations for routines called by application. * The JPP macro hides prototype parameters from compilers that can't cope. * Note JPP requires double parentheses. */ #ifdef HAVE_PROTOTYPES #define JPP(arglist) arglist #else #define JPP(arglist) () #endif /* Short forms of external names for systems with brain-damaged linkers. * We shorten external names to be unique in the first six letters, which * is good enough for all known systems. * (If your compiler itself needs names to be unique in less than 15 * characters, you are out of luck. Get a better compiler.) */ #ifdef NEED_SHORT_EXTERNAL_NAMES #define jpeg_std_error jStdError #define jpeg_CreateCompress jCreaCompress #define jpeg_CreateDecompress jCreaDecompress #define jpeg_destroy_compress jDestCompress #define jpeg_destroy_decompress jDestDecompress #define jpeg_stdio_dest jStdDest #define jpeg_stdio_src jStdSrc #define jpeg_set_defaults jSetDefaults #define jpeg_set_colorspace jSetColorspace #define jpeg_default_colorspace jDefColorspace #define jpeg_set_quality jSetQuality #define jpeg_set_linear_quality jSetLQuality #define jpeg_add_quant_table jAddQuantTable #define jpeg_quality_scaling jQualityScaling #define jpeg_simple_progression jSimProgress #define jpeg_suppress_tables jSuppressTables #define jpeg_alloc_quant_table jAlcQTable #define jpeg_alloc_huff_table jAlcHTable #define jpeg_start_compress jStrtCompress #define jpeg_write_scanlines jWrtScanlines #define jpeg_finish_compress jFinCompress #define jpeg_write_raw_data jWrtRawData #define jpeg_write_marker jWrtMarker #define jpeg_write_m_header jWrtMHeader #define jpeg_write_m_byte jWrtMByte #define jpeg_write_tables jWrtTables #define jpeg_read_header jReadHeader #define jpeg_start_decompress jStrtDecompress #define jpeg_read_scanlines jReadScanlines #define jpeg_finish_decompress jFinDecompress #define jpeg_read_raw_data jReadRawData #define jpeg_has_multiple_scans jHasMultScn #define jpeg_start_output jStrtOutput #define jpeg_finish_output jFinOutput #define jpeg_input_complete jInComplete #define jpeg_new_colormap jNewCMap #define jpeg_consume_input jConsumeInput #define jpeg_calc_output_dimensions jCalcDimensions #define jpeg_save_markers jSaveMarkers #define jpeg_set_marker_processor jSetMarker #define jpeg_read_coefficients jReadCoefs #define jpeg_write_coefficients jWrtCoefs #define jpeg_copy_critical_parameters jCopyCrit #define jpeg_abort_compress jAbrtCompress #define jpeg_abort_decompress jAbrtDecompress #define jpeg_abort jAbort #define jpeg_destroy jDestroy #define jpeg_resync_to_restart jResyncRestart #endif /* NEED_SHORT_EXTERNAL_NAMES */ /* Default error-management setup */ EXTERN(struct jpeg_error_mgr *) jpeg_std_error JPP((struct jpeg_error_mgr * err)); /* Initialization of JPEG compression objects. * jpeg_create_compress() and jpeg_create_decompress() are the exported * names that applications should call. These expand to calls on * jpeg_CreateCompress and jpeg_CreateDecompress with additional information * passed for version mismatch checking. * NB: you must set up the error-manager BEFORE calling jpeg_create_xxx. */ #define jpeg_create_compress(cinfo) \ jpeg_CreateCompress((cinfo), JPEG_LIB_VERSION, \ (size_t) sizeof(struct jpeg_compress_struct)) #define jpeg_create_decompress(cinfo) \ jpeg_CreateDecompress((cinfo), JPEG_LIB_VERSION, \ (size_t) sizeof(struct jpeg_decompress_struct)) EXTERN(void) jpeg_CreateCompress JPP((j_compress_ptr cinfo, int version, size_t structsize)); EXTERN(void) jpeg_CreateDecompress JPP((j_decompress_ptr cinfo, int version, size_t structsize)); /* Destruction of JPEG compression objects */ EXTERN(void) jpeg_destroy_compress JPP((j_compress_ptr cinfo)); EXTERN(void) jpeg_destroy_decompress JPP((j_decompress_ptr cinfo)); /* Standard data source and destination managers: stdio streams. */ /* Caller is responsible for opening the file before and closing after. */ EXTERN(void) jpeg_stdio_dest JPP((j_compress_ptr cinfo, FILE * outfile)); EXTERN(void) jpeg_stdio_src JPP((j_decompress_ptr cinfo, FILE * infile)); /* Default parameter setup for compression */ EXTERN(void) jpeg_set_defaults JPP((j_compress_ptr cinfo)); /* Compression parameter setup aids */ EXTERN(void) jpeg_set_colorspace JPP((j_compress_ptr cinfo, J_COLOR_SPACE colorspace)); EXTERN(void) jpeg_default_colorspace JPP((j_compress_ptr cinfo)); EXTERN(void) jpeg_set_quality JPP((j_compress_ptr cinfo, int quality, boolean force_baseline)); EXTERN(void) jpeg_set_linear_quality JPP((j_compress_ptr cinfo, int scale_factor, boolean force_baseline)); EXTERN(void) jpeg_add_quant_table JPP((j_compress_ptr cinfo, int which_tbl, const unsigned int *basic_table, int scale_factor, boolean force_baseline)); EXTERN(int) jpeg_quality_scaling JPP((int quality)); EXTERN(void) jpeg_simple_progression JPP((j_compress_ptr cinfo)); EXTERN(void) jpeg_suppress_tables JPP((j_compress_ptr cinfo, boolean suppress)); EXTERN(JQUANT_TBL *) jpeg_alloc_quant_table JPP((j_common_ptr cinfo)); EXTERN(JHUFF_TBL *) jpeg_alloc_huff_table JPP((j_common_ptr cinfo)); /* Main entry points for compression */ EXTERN(void) jpeg_start_compress JPP((j_compress_ptr cinfo, boolean write_all_tables)); EXTERN(JDIMENSION) jpeg_write_scanlines JPP((j_compress_ptr cinfo, JSAMPARRAY scanlines, JDIMENSION num_lines)); EXTERN(void) jpeg_finish_compress JPP((j_compress_ptr cinfo)); /* Replaces jpeg_write_scanlines when writing raw downsampled data. */ EXTERN(JDIMENSION) jpeg_write_raw_data JPP((j_compress_ptr cinfo, JSAMPIMAGE data, JDIMENSION num_lines)); /* Write a special marker. See libjpeg.doc concerning safe usage. */ EXTERN(void) jpeg_write_marker JPP((j_compress_ptr cinfo, int marker, const JOCTET * dataptr, unsigned int datalen)); /* Same, but piecemeal. */ EXTERN(void) jpeg_write_m_header JPP((j_compress_ptr cinfo, int marker, unsigned int datalen)); EXTERN(void) jpeg_write_m_byte JPP((j_compress_ptr cinfo, int val)); /* Alternate compression function: just write an abbreviated table file */ EXTERN(void) jpeg_write_tables JPP((j_compress_ptr cinfo)); /* Decompression startup: read start of JPEG datastream to see what's there */ EXTERN(int) jpeg_read_header JPP((j_decompress_ptr cinfo, boolean require_image)); /* Return value is one of: */ #define JPEG_SUSPENDED 0 /* Suspended due to lack of input data */ #define JPEG_HEADER_OK 1 /* Found valid image datastream */ #define JPEG_HEADER_TABLES_ONLY 2 /* Found valid table-specs-only datastream */ /* If you pass require_image = TRUE (normal case), you need not check for * a TABLES_ONLY return code; an abbreviated file will cause an error exit. * JPEG_SUSPENDED is only possible if you use a data source module that can * give a suspension return (the stdio source module doesn't). */ /* Main entry points for decompression */ EXTERN(boolean) jpeg_start_decompress JPP((j_decompress_ptr cinfo)); EXTERN(JDIMENSION) jpeg_read_scanlines JPP((j_decompress_ptr cinfo, JSAMPARRAY scanlines, JDIMENSION max_lines)); EXTERN(boolean) jpeg_finish_decompress JPP((j_decompress_ptr cinfo)); /* Replaces jpeg_read_scanlines when reading raw downsampled data. */ EXTERN(JDIMENSION) jpeg_read_raw_data JPP((j_decompress_ptr cinfo, JSAMPIMAGE data, JDIMENSION max_lines)); /* Additional entry points for buffered-image mode. */ EXTERN(boolean) jpeg_has_multiple_scans JPP((j_decompress_ptr cinfo)); EXTERN(boolean) jpeg_start_output JPP((j_decompress_ptr cinfo, int scan_number)); EXTERN(boolean) jpeg_finish_output JPP((j_decompress_ptr cinfo)); EXTERN(boolean) jpeg_input_complete JPP((j_decompress_ptr cinfo)); EXTERN(void) jpeg_new_colormap JPP((j_decompress_ptr cinfo)); EXTERN(int) jpeg_consume_input JPP((j_decompress_ptr cinfo)); /* Return value is one of: */ /* #define JPEG_SUSPENDED 0 Suspended due to lack of input data */ #define JPEG_REACHED_SOS 1 /* Reached start of new scan */ #define JPEG_REACHED_EOI 2 /* Reached end of image */ #define JPEG_ROW_COMPLETED 3 /* Completed one iMCU row */ #define JPEG_SCAN_COMPLETED 4 /* Completed last iMCU row of a scan */ /* Precalculate output dimensions for current decompression parameters. */ EXTERN(void) jpeg_calc_output_dimensions JPP((j_decompress_ptr cinfo)); /* Control saving of COM and APPn markers into marker_list. */ EXTERN(void) jpeg_save_markers JPP((j_decompress_ptr cinfo, int marker_code, unsigned int length_limit)); /* Install a special processing method for COM or APPn markers. */ EXTERN(void) jpeg_set_marker_processor JPP((j_decompress_ptr cinfo, int marker_code, jpeg_marker_parser_method routine)); /* Read or write raw DCT coefficients --- useful for lossless transcoding. */ EXTERN(jvirt_barray_ptr *) jpeg_read_coefficients JPP((j_decompress_ptr cinfo)); EXTERN(void) jpeg_write_coefficients JPP((j_compress_ptr cinfo, jvirt_barray_ptr * coef_arrays)); EXTERN(void) jpeg_copy_critical_parameters JPP((j_decompress_ptr srcinfo, j_compress_ptr dstinfo)); /* If you choose to abort compression or decompression before completing * jpeg_finish_(de)compress, then you need to clean up to release memory, * temporary files, etc. You can just call jpeg_destroy_(de)compress * if you're done with the JPEG object, but if you want to clean it up and * reuse it, call this: */ EXTERN(void) jpeg_abort_compress JPP((j_compress_ptr cinfo)); EXTERN(void) jpeg_abort_decompress JPP((j_decompress_ptr cinfo)); /* Generic versions of jpeg_abort and jpeg_destroy that work on either * flavor of JPEG object. These may be more convenient in some places. */ EXTERN(void) jpeg_abort JPP((j_common_ptr cinfo)); EXTERN(void) jpeg_destroy JPP((j_common_ptr cinfo)); /* Default restart-marker-resync procedure for use by data source modules */ EXTERN(boolean) jpeg_resync_to_restart JPP((j_decompress_ptr cinfo, int desired)); /* These marker codes are exported since applications and data source modules * are likely to want to use them. */ #define JPEG_RST0 0xD0 /* RST0 marker code */ #define JPEG_EOI 0xD9 /* EOI marker code */ #define JPEG_APP0 0xE0 /* APP0 marker code */ #define JPEG_COM 0xFE /* COM marker code */ /* If we have a brain-damaged compiler that emits warnings (or worse, errors) * for structure definitions that are never filled in, keep it quiet by * supplying dummy definitions for the various substructures. */ #ifdef INCOMPLETE_TYPES_BROKEN #ifndef JPEG_INTERNALS /* will be defined in jpegint.h */ struct jvirt_sarray_control { long dummy; }; struct jvirt_barray_control { long dummy; }; struct jpeg_comp_master { long dummy; }; struct jpeg_c_main_controller { long dummy; }; struct jpeg_c_prep_controller { long dummy; }; struct jpeg_c_coef_controller { long dummy; }; struct jpeg_marker_writer { long dummy; }; struct jpeg_color_converter { long dummy; }; struct jpeg_downsampler { long dummy; }; struct jpeg_forward_dct { long dummy; }; struct jpeg_entropy_encoder { long dummy; }; struct jpeg_decomp_master { long dummy; }; struct jpeg_d_main_controller { long dummy; }; struct jpeg_d_coef_controller { long dummy; }; struct jpeg_d_post_controller { long dummy; }; struct jpeg_input_controller { long dummy; }; struct jpeg_marker_reader { long dummy; }; struct jpeg_entropy_decoder { long dummy; }; struct jpeg_inverse_dct { long dummy; }; struct jpeg_upsampler { long dummy; }; struct jpeg_color_deconverter { long dummy; }; struct jpeg_color_quantizer { long dummy; }; #endif /* JPEG_INTERNALS */ #endif /* INCOMPLETE_TYPES_BROKEN */ /* * The JPEG library modules define JPEG_INTERNALS before including this file. * The internal structure declarations are read only when that is true. * Applications using the library should not include jpegint.h, but may wish * to include jerror.h. */ #ifdef JPEG_INTERNALS #include "jpegint.h" /* fetch private declarations */ #include "jerror.h" /* fetch error codes too */ #endif #endif /* JPEGLIB_H */ fbi-2.10/jpeg/62/jinclude.h0000644000175000017500000000626212506525033013455 0ustar jmmjmm/* * jinclude.h * * Copyright (C) 1991-1994, Thomas G. Lane. * This file is part of the Independent JPEG Group's software. * For conditions of distribution and use, see the accompanying README file. * * This file exists to provide a single place to fix any problems with * including the wrong system include files. (Common problems are taken * care of by the standard jconfig symbols, but on really weird systems * you may have to edit this file.) * * NOTE: this file is NOT intended to be included by applications using the * JPEG library. Most applications need only include jpeglib.h. */ /* Include auto-config file to find out which system include files we need. */ #include "jconfig.h" /* auto configuration options */ #define JCONFIG_INCLUDED /* so that jpeglib.h doesn't do it again */ /* * We need the NULL macro and size_t typedef. * On an ANSI-conforming system it is sufficient to include . * Otherwise, we get them from or ; we may have to * pull in as well. * Note that the core JPEG library does not require ; * only the default error handler and data source/destination modules do. * But we must pull it in because of the references to FILE in jpeglib.h. * You can remove those references if you want to compile without . */ #ifdef HAVE_STDDEF_H #include #endif #ifdef HAVE_STDLIB_H #include #endif #ifdef NEED_SYS_TYPES_H #include #endif #include /* * We need memory copying and zeroing functions, plus strncpy(). * ANSI and System V implementations declare these in . * BSD doesn't have the mem() functions, but it does have bcopy()/bzero(). * Some systems may declare memset and memcpy in . * * NOTE: we assume the size parameters to these functions are of type size_t. * Change the casts in these macros if not! */ #ifdef NEED_BSD_STRINGS #include #define MEMZERO(target,size) bzero((void *)(target), (size_t)(size)) #define MEMCOPY(dest,src,size) bcopy((const void *)(src), (void *)(dest), (size_t)(size)) #else /* not BSD, assume ANSI/SysV string lib */ #include #define MEMZERO(target,size) memset((void *)(target), 0, (size_t)(size)) #define MEMCOPY(dest,src,size) memcpy((void *)(dest), (const void *)(src), (size_t)(size)) #endif /* * In ANSI C, and indeed any rational implementation, size_t is also the * type returned by sizeof(). However, it seems there are some irrational * implementations out there, in which sizeof() returns an int even though * size_t is defined as long or unsigned long. To ensure consistent results * we always use this SIZEOF() macro in place of using sizeof() directly. */ #define SIZEOF(object) ((size_t) sizeof(object)) /* * The modules that use fread() and fwrite() always invoke them through * these macros. On some systems you may need to twiddle the argument casts. * CAUTION: argument order is different from underlying functions! */ #define JFREAD(file,buf,sizeofbuf) \ ((size_t) fread((void *) (buf), (size_t) 1, (size_t) (sizeofbuf), (file))) #define JFWRITE(file,buf,sizeofbuf) \ ((size_t) fwrite((const void *) (buf), (size_t) 1, (size_t) (sizeofbuf), (file))) fbi-2.10/jpeg/62/transupp.h0000644000175000017500000001320112506525033013523 0ustar jmmjmm/* * transupp.h * * Copyright (C) 1997, Thomas G. Lane. * This file is part of the Independent JPEG Group's software. * For conditions of distribution and use, see the accompanying README file. * * This file contains declarations for image transformation routines and * other utility code used by the jpegtran sample application. These are * NOT part of the core JPEG library. But we keep these routines separate * from jpegtran.c to ease the task of maintaining jpegtran-like programs * that have other user interfaces. * * NOTE: all the routines declared here have very specific requirements * about when they are to be executed during the reading and writing of the * source and destination files. See the comments in transupp.c, or see * jpegtran.c for an example of correct usage. */ /* If you happen not to want the image transform support, disable it here */ #ifndef TRANSFORMS_SUPPORTED #define TRANSFORMS_SUPPORTED 1 /* 0 disables transform code */ #endif /* Short forms of external names for systems with brain-damaged linkers. */ #ifdef NEED_SHORT_EXTERNAL_NAMES #define jtransform_request_workspace jTrRequest #define jtransform_adjust_parameters jTrAdjust #define jtransform_execute_transformation jTrExec #define jcopy_markers_setup jCMrkSetup #define jcopy_markers_execute jCMrkExec #endif /* NEED_SHORT_EXTERNAL_NAMES */ /* * Codes for supported types of image transformations. */ typedef enum { JXFORM_NONE, /* no transformation */ JXFORM_FLIP_H, /* horizontal flip */ JXFORM_FLIP_V, /* vertical flip */ JXFORM_TRANSPOSE, /* transpose across UL-to-LR axis */ JXFORM_TRANSVERSE, /* transpose across UR-to-LL axis */ JXFORM_ROT_90, /* 90-degree clockwise rotation */ JXFORM_ROT_180, /* 180-degree rotation */ JXFORM_ROT_270 /* 270-degree clockwise (or 90 ccw) */ } JXFORM_CODE; /* * Although rotating and flipping data expressed as DCT coefficients is not * hard, there is an asymmetry in the JPEG format specification for images * whose dimensions aren't multiples of the iMCU size. The right and bottom * image edges are padded out to the next iMCU boundary with junk data; but * no padding is possible at the top and left edges. If we were to flip * the whole image including the pad data, then pad garbage would become * visible at the top and/or left, and real pixels would disappear into the * pad margins --- perhaps permanently, since encoders & decoders may not * bother to preserve DCT blocks that appear to be completely outside the * nominal image area. So, we have to exclude any partial iMCUs from the * basic transformation. * * Transpose is the only transformation that can handle partial iMCUs at the * right and bottom edges completely cleanly. flip_h can flip partial iMCUs * at the bottom, but leaves any partial iMCUs at the right edge untouched. * Similarly flip_v leaves any partial iMCUs at the bottom edge untouched. * The other transforms are defined as combinations of these basic transforms * and process edge blocks in a way that preserves the equivalence. * * The "trim" option causes untransformable partial iMCUs to be dropped; * this is not strictly lossless, but it usually gives the best-looking * result for odd-size images. Note that when this option is active, * the expected mathematical equivalences between the transforms may not hold. * (For example, -rot 270 -trim trims only the bottom edge, but -rot 90 -trim * followed by -rot 180 -trim trims both edges.) * * We also offer a "force to grayscale" option, which simply discards the * chrominance channels of a YCbCr image. This is lossless in the sense that * the luminance channel is preserved exactly. It's not the same kind of * thing as the rotate/flip transformations, but it's convenient to handle it * as part of this package, mainly because the transformation routines have to * be aware of the option to know how many components to work on. */ typedef struct { /* Options: set by caller */ JXFORM_CODE transform; /* image transform operator */ boolean trim; /* if TRUE, trim partial MCUs as needed */ boolean force_grayscale; /* if TRUE, convert color image to grayscale */ /* Internal workspace: caller should not touch these */ int num_components; /* # of components in workspace */ jvirt_barray_ptr * workspace_coef_arrays; /* workspace for transformations */ } jpeg_transform_info; #if TRANSFORMS_SUPPORTED /* Request any required workspace */ EXTERN(void) jtransform_request_workspace JPP((j_decompress_ptr srcinfo, jpeg_transform_info *info)); /* Adjust output image parameters */ EXTERN(jvirt_barray_ptr *) jtransform_adjust_parameters JPP((j_decompress_ptr srcinfo, j_compress_ptr dstinfo, jvirt_barray_ptr *src_coef_arrays, jpeg_transform_info *info)); /* Execute the actual transformation, if any */ EXTERN(void) jtransform_execute_transformation JPP((j_decompress_ptr srcinfo, j_compress_ptr dstinfo, jvirt_barray_ptr *src_coef_arrays, jpeg_transform_info *info)); #endif /* TRANSFORMS_SUPPORTED */ /* * Support for copying optional markers from source to destination file. */ typedef enum { JCOPYOPT_NONE, /* copy no optional markers */ JCOPYOPT_COMMENTS, /* copy only comment (COM) markers */ JCOPYOPT_ALL /* copy all optional markers */ } JCOPY_OPTION; #define JCOPYOPT_DEFAULT JCOPYOPT_COMMENTS /* recommended default */ /* Setup decompression object to save desired markers in memory */ EXTERN(void) jcopy_markers_setup JPP((j_decompress_ptr srcinfo, JCOPY_OPTION option)); /* Copy markers saved in the given source object to the destination object */ EXTERN(void) jcopy_markers_execute JPP((j_decompress_ptr srcinfo, j_compress_ptr dstinfo, JCOPY_OPTION option)); fbi-2.10/jpeg/62/jpegint.h0000644000175000017500000003654012506525033013322 0ustar jmmjmm/* * jpegint.h * * Copyright (C) 1991-1997, Thomas G. Lane. * This file is part of the Independent JPEG Group's software. * For conditions of distribution and use, see the accompanying README file. * * This file provides common declarations for the various JPEG modules. * These declarations are considered internal to the JPEG library; most * applications using the library shouldn't need to include this file. */ /* Declarations for both compression & decompression */ typedef enum { /* Operating modes for buffer controllers */ JBUF_PASS_THRU, /* Plain stripwise operation */ /* Remaining modes require a full-image buffer to have been created */ JBUF_SAVE_SOURCE, /* Run source subobject only, save output */ JBUF_CRANK_DEST, /* Run dest subobject only, using saved data */ JBUF_SAVE_AND_PASS /* Run both subobjects, save output */ } J_BUF_MODE; /* Values of global_state field (jdapi.c has some dependencies on ordering!) */ #define CSTATE_START 100 /* after create_compress */ #define CSTATE_SCANNING 101 /* start_compress done, write_scanlines OK */ #define CSTATE_RAW_OK 102 /* start_compress done, write_raw_data OK */ #define CSTATE_WRCOEFS 103 /* jpeg_write_coefficients done */ #define DSTATE_START 200 /* after create_decompress */ #define DSTATE_INHEADER 201 /* reading header markers, no SOS yet */ #define DSTATE_READY 202 /* found SOS, ready for start_decompress */ #define DSTATE_PRELOAD 203 /* reading multiscan file in start_decompress*/ #define DSTATE_PRESCAN 204 /* performing dummy pass for 2-pass quant */ #define DSTATE_SCANNING 205 /* start_decompress done, read_scanlines OK */ #define DSTATE_RAW_OK 206 /* start_decompress done, read_raw_data OK */ #define DSTATE_BUFIMAGE 207 /* expecting jpeg_start_output */ #define DSTATE_BUFPOST 208 /* looking for SOS/EOI in jpeg_finish_output */ #define DSTATE_RDCOEFS 209 /* reading file in jpeg_read_coefficients */ #define DSTATE_STOPPING 210 /* looking for EOI in jpeg_finish_decompress */ /* Declarations for compression modules */ /* Master control module */ struct jpeg_comp_master { JMETHOD(void, prepare_for_pass, (j_compress_ptr cinfo)); JMETHOD(void, pass_startup, (j_compress_ptr cinfo)); JMETHOD(void, finish_pass, (j_compress_ptr cinfo)); /* State variables made visible to other modules */ boolean call_pass_startup; /* True if pass_startup must be called */ boolean is_last_pass; /* True during last pass */ }; /* Main buffer control (downsampled-data buffer) */ struct jpeg_c_main_controller { JMETHOD(void, start_pass, (j_compress_ptr cinfo, J_BUF_MODE pass_mode)); JMETHOD(void, process_data, (j_compress_ptr cinfo, JSAMPARRAY input_buf, JDIMENSION *in_row_ctr, JDIMENSION in_rows_avail)); }; /* Compression preprocessing (downsampling input buffer control) */ struct jpeg_c_prep_controller { JMETHOD(void, start_pass, (j_compress_ptr cinfo, J_BUF_MODE pass_mode)); JMETHOD(void, pre_process_data, (j_compress_ptr cinfo, JSAMPARRAY input_buf, JDIMENSION *in_row_ctr, JDIMENSION in_rows_avail, JSAMPIMAGE output_buf, JDIMENSION *out_row_group_ctr, JDIMENSION out_row_groups_avail)); }; /* Coefficient buffer control */ struct jpeg_c_coef_controller { JMETHOD(void, start_pass, (j_compress_ptr cinfo, J_BUF_MODE pass_mode)); JMETHOD(boolean, compress_data, (j_compress_ptr cinfo, JSAMPIMAGE input_buf)); }; /* Colorspace conversion */ struct jpeg_color_converter { JMETHOD(void, start_pass, (j_compress_ptr cinfo)); JMETHOD(void, color_convert, (j_compress_ptr cinfo, JSAMPARRAY input_buf, JSAMPIMAGE output_buf, JDIMENSION output_row, int num_rows)); }; /* Downsampling */ struct jpeg_downsampler { JMETHOD(void, start_pass, (j_compress_ptr cinfo)); JMETHOD(void, downsample, (j_compress_ptr cinfo, JSAMPIMAGE input_buf, JDIMENSION in_row_index, JSAMPIMAGE output_buf, JDIMENSION out_row_group_index)); boolean need_context_rows; /* TRUE if need rows above & below */ }; /* Forward DCT (also controls coefficient quantization) */ struct jpeg_forward_dct { JMETHOD(void, start_pass, (j_compress_ptr cinfo)); /* perhaps this should be an array??? */ JMETHOD(void, forward_DCT, (j_compress_ptr cinfo, jpeg_component_info * compptr, JSAMPARRAY sample_data, JBLOCKROW coef_blocks, JDIMENSION start_row, JDIMENSION start_col, JDIMENSION num_blocks)); }; /* Entropy encoding */ struct jpeg_entropy_encoder { JMETHOD(void, start_pass, (j_compress_ptr cinfo, boolean gather_statistics)); JMETHOD(boolean, encode_mcu, (j_compress_ptr cinfo, JBLOCKROW *MCU_data)); JMETHOD(void, finish_pass, (j_compress_ptr cinfo)); }; /* Marker writing */ struct jpeg_marker_writer { JMETHOD(void, write_file_header, (j_compress_ptr cinfo)); JMETHOD(void, write_frame_header, (j_compress_ptr cinfo)); JMETHOD(void, write_scan_header, (j_compress_ptr cinfo)); JMETHOD(void, write_file_trailer, (j_compress_ptr cinfo)); JMETHOD(void, write_tables_only, (j_compress_ptr cinfo)); /* These routines are exported to allow insertion of extra markers */ /* Probably only COM and APPn markers should be written this way */ JMETHOD(void, write_marker_header, (j_compress_ptr cinfo, int marker, unsigned int datalen)); JMETHOD(void, write_marker_byte, (j_compress_ptr cinfo, int val)); }; /* Declarations for decompression modules */ /* Master control module */ struct jpeg_decomp_master { JMETHOD(void, prepare_for_output_pass, (j_decompress_ptr cinfo)); JMETHOD(void, finish_output_pass, (j_decompress_ptr cinfo)); /* State variables made visible to other modules */ boolean is_dummy_pass; /* True during 1st pass for 2-pass quant */ }; /* Input control module */ struct jpeg_input_controller { JMETHOD(int, consume_input, (j_decompress_ptr cinfo)); JMETHOD(void, reset_input_controller, (j_decompress_ptr cinfo)); JMETHOD(void, start_input_pass, (j_decompress_ptr cinfo)); JMETHOD(void, finish_input_pass, (j_decompress_ptr cinfo)); /* State variables made visible to other modules */ boolean has_multiple_scans; /* True if file has multiple scans */ boolean eoi_reached; /* True when EOI has been consumed */ }; /* Main buffer control (downsampled-data buffer) */ struct jpeg_d_main_controller { JMETHOD(void, start_pass, (j_decompress_ptr cinfo, J_BUF_MODE pass_mode)); JMETHOD(void, process_data, (j_decompress_ptr cinfo, JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, JDIMENSION out_rows_avail)); }; /* Coefficient buffer control */ struct jpeg_d_coef_controller { JMETHOD(void, start_input_pass, (j_decompress_ptr cinfo)); JMETHOD(int, consume_data, (j_decompress_ptr cinfo)); JMETHOD(void, start_output_pass, (j_decompress_ptr cinfo)); JMETHOD(int, decompress_data, (j_decompress_ptr cinfo, JSAMPIMAGE output_buf)); /* Pointer to array of coefficient virtual arrays, or NULL if none */ jvirt_barray_ptr *coef_arrays; }; /* Decompression postprocessing (color quantization buffer control) */ struct jpeg_d_post_controller { JMETHOD(void, start_pass, (j_decompress_ptr cinfo, J_BUF_MODE pass_mode)); JMETHOD(void, post_process_data, (j_decompress_ptr cinfo, JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr, JDIMENSION in_row_groups_avail, JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, JDIMENSION out_rows_avail)); }; /* Marker reading & parsing */ struct jpeg_marker_reader { JMETHOD(void, reset_marker_reader, (j_decompress_ptr cinfo)); /* Read markers until SOS or EOI. * Returns same codes as are defined for jpeg_consume_input: * JPEG_SUSPENDED, JPEG_REACHED_SOS, or JPEG_REACHED_EOI. */ JMETHOD(int, read_markers, (j_decompress_ptr cinfo)); /* Read a restart marker --- exported for use by entropy decoder only */ jpeg_marker_parser_method read_restart_marker; /* State of marker reader --- nominally internal, but applications * supplying COM or APPn handlers might like to know the state. */ boolean saw_SOI; /* found SOI? */ boolean saw_SOF; /* found SOF? */ int next_restart_num; /* next restart number expected (0-7) */ unsigned int discarded_bytes; /* # of bytes skipped looking for a marker */ }; /* Entropy decoding */ struct jpeg_entropy_decoder { JMETHOD(void, start_pass, (j_decompress_ptr cinfo)); JMETHOD(boolean, decode_mcu, (j_decompress_ptr cinfo, JBLOCKROW *MCU_data)); /* This is here to share code between baseline and progressive decoders; */ /* other modules probably should not use it */ boolean insufficient_data; /* set TRUE after emitting warning */ }; /* Inverse DCT (also performs dequantization) */ typedef JMETHOD(void, inverse_DCT_method_ptr, (j_decompress_ptr cinfo, jpeg_component_info * compptr, JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); struct jpeg_inverse_dct { JMETHOD(void, start_pass, (j_decompress_ptr cinfo)); /* It is useful to allow each component to have a separate IDCT method. */ inverse_DCT_method_ptr inverse_DCT[MAX_COMPONENTS]; }; /* Upsampling (note that upsampler must also call color converter) */ struct jpeg_upsampler { JMETHOD(void, start_pass, (j_decompress_ptr cinfo)); JMETHOD(void, upsample, (j_decompress_ptr cinfo, JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr, JDIMENSION in_row_groups_avail, JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, JDIMENSION out_rows_avail)); boolean need_context_rows; /* TRUE if need rows above & below */ }; /* Colorspace conversion */ struct jpeg_color_deconverter { JMETHOD(void, start_pass, (j_decompress_ptr cinfo)); JMETHOD(void, color_convert, (j_decompress_ptr cinfo, JSAMPIMAGE input_buf, JDIMENSION input_row, JSAMPARRAY output_buf, int num_rows)); }; /* Color quantization or color precision reduction */ struct jpeg_color_quantizer { JMETHOD(void, start_pass, (j_decompress_ptr cinfo, boolean is_pre_scan)); JMETHOD(void, color_quantize, (j_decompress_ptr cinfo, JSAMPARRAY input_buf, JSAMPARRAY output_buf, int num_rows)); JMETHOD(void, finish_pass, (j_decompress_ptr cinfo)); JMETHOD(void, new_color_map, (j_decompress_ptr cinfo)); }; /* Miscellaneous useful macros */ #undef MAX #define MAX(a,b) ((a) > (b) ? (a) : (b)) #undef MIN #define MIN(a,b) ((a) < (b) ? (a) : (b)) /* We assume that right shift corresponds to signed division by 2 with * rounding towards minus infinity. This is correct for typical "arithmetic * shift" instructions that shift in copies of the sign bit. But some * C compilers implement >> with an unsigned shift. For these machines you * must define RIGHT_SHIFT_IS_UNSIGNED. * RIGHT_SHIFT provides a proper signed right shift of an INT32 quantity. * It is only applied with constant shift counts. SHIFT_TEMPS must be * included in the variables of any routine using RIGHT_SHIFT. */ #ifdef RIGHT_SHIFT_IS_UNSIGNED #define SHIFT_TEMPS INT32 shift_temp; #define RIGHT_SHIFT(x,shft) \ ((shift_temp = (x)) < 0 ? \ (shift_temp >> (shft)) | ((~((INT32) 0)) << (32-(shft))) : \ (shift_temp >> (shft))) #else #define SHIFT_TEMPS #define RIGHT_SHIFT(x,shft) ((x) >> (shft)) #endif /* Short forms of external names for systems with brain-damaged linkers. */ #ifdef NEED_SHORT_EXTERNAL_NAMES #define jinit_compress_master jICompress #define jinit_c_master_control jICMaster #define jinit_c_main_controller jICMainC #define jinit_c_prep_controller jICPrepC #define jinit_c_coef_controller jICCoefC #define jinit_color_converter jICColor #define jinit_downsampler jIDownsampler #define jinit_forward_dct jIFDCT #define jinit_huff_encoder jIHEncoder #define jinit_phuff_encoder jIPHEncoder #define jinit_marker_writer jIMWriter #define jinit_master_decompress jIDMaster #define jinit_d_main_controller jIDMainC #define jinit_d_coef_controller jIDCoefC #define jinit_d_post_controller jIDPostC #define jinit_input_controller jIInCtlr #define jinit_marker_reader jIMReader #define jinit_huff_decoder jIHDecoder #define jinit_phuff_decoder jIPHDecoder #define jinit_inverse_dct jIIDCT #define jinit_upsampler jIUpsampler #define jinit_color_deconverter jIDColor #define jinit_1pass_quantizer jI1Quant #define jinit_2pass_quantizer jI2Quant #define jinit_merged_upsampler jIMUpsampler #define jinit_memory_mgr jIMemMgr #define jdiv_round_up jDivRound #define jround_up jRound #define jcopy_sample_rows jCopySamples #define jcopy_block_row jCopyBlocks #define jzero_far jZeroFar #define jpeg_zigzag_order jZIGTable #define jpeg_natural_order jZAGTable #endif /* NEED_SHORT_EXTERNAL_NAMES */ /* Compression module initialization routines */ EXTERN(void) jinit_compress_master JPP((j_compress_ptr cinfo)); EXTERN(void) jinit_c_master_control JPP((j_compress_ptr cinfo, boolean transcode_only)); EXTERN(void) jinit_c_main_controller JPP((j_compress_ptr cinfo, boolean need_full_buffer)); EXTERN(void) jinit_c_prep_controller JPP((j_compress_ptr cinfo, boolean need_full_buffer)); EXTERN(void) jinit_c_coef_controller JPP((j_compress_ptr cinfo, boolean need_full_buffer)); EXTERN(void) jinit_color_converter JPP((j_compress_ptr cinfo)); EXTERN(void) jinit_downsampler JPP((j_compress_ptr cinfo)); EXTERN(void) jinit_forward_dct JPP((j_compress_ptr cinfo)); EXTERN(void) jinit_huff_encoder JPP((j_compress_ptr cinfo)); EXTERN(void) jinit_phuff_encoder JPP((j_compress_ptr cinfo)); EXTERN(void) jinit_marker_writer JPP((j_compress_ptr cinfo)); /* Decompression module initialization routines */ EXTERN(void) jinit_master_decompress JPP((j_decompress_ptr cinfo)); EXTERN(void) jinit_d_main_controller JPP((j_decompress_ptr cinfo, boolean need_full_buffer)); EXTERN(void) jinit_d_coef_controller JPP((j_decompress_ptr cinfo, boolean need_full_buffer)); EXTERN(void) jinit_d_post_controller JPP((j_decompress_ptr cinfo, boolean need_full_buffer)); EXTERN(void) jinit_input_controller JPP((j_decompress_ptr cinfo)); EXTERN(void) jinit_marker_reader JPP((j_decompress_ptr cinfo)); EXTERN(void) jinit_huff_decoder JPP((j_decompress_ptr cinfo)); EXTERN(void) jinit_phuff_decoder JPP((j_decompress_ptr cinfo)); EXTERN(void) jinit_inverse_dct JPP((j_decompress_ptr cinfo)); EXTERN(void) jinit_upsampler JPP((j_decompress_ptr cinfo)); EXTERN(void) jinit_color_deconverter JPP((j_decompress_ptr cinfo)); EXTERN(void) jinit_1pass_quantizer JPP((j_decompress_ptr cinfo)); EXTERN(void) jinit_2pass_quantizer JPP((j_decompress_ptr cinfo)); EXTERN(void) jinit_merged_upsampler JPP((j_decompress_ptr cinfo)); /* Memory manager initialization */ EXTERN(void) jinit_memory_mgr JPP((j_common_ptr cinfo)); /* Utility routines in jutils.c */ EXTERN(long) jdiv_round_up JPP((long a, long b)); EXTERN(long) jround_up JPP((long a, long b)); EXTERN(void) jcopy_sample_rows JPP((JSAMPARRAY input_array, int source_row, JSAMPARRAY output_array, int dest_row, int num_rows, JDIMENSION num_cols)); EXTERN(void) jcopy_block_row JPP((JBLOCKROW input_row, JBLOCKROW output_row, JDIMENSION num_blocks)); EXTERN(void) jzero_far JPP((void FAR * target, size_t bytestozero)); /* Constant tables in jutils.c */ #if 0 /* This table is not actually needed in v6a */ extern const int jpeg_zigzag_order[]; /* natural coef order to zigzag order */ #endif extern const int jpeg_natural_order[]; /* zigzag coef order to natural order */ /* Suppress undefined-structure complaints if necessary. */ #ifdef INCOMPLETE_TYPES_BROKEN #ifndef AM_MEMORY_MANAGER /* only jmemmgr.c defines these */ struct jvirt_sarray_control { long dummy; }; struct jvirt_barray_control { long dummy; }; #endif #endif /* INCOMPLETE_TYPES_BROKEN */ fbi-2.10/jpeg/90/0000755000175000017500000000000012506525033011502 5ustar jmmjmmfbi-2.10/jpeg/90/transupp.c0000644000175000017500000017435012506525033013534 0ustar jmmjmm/* * transupp.c * * Copyright (C) 1997-2013, Thomas G. Lane, Guido Vollbeding. * This file is part of the Independent JPEG Group's software. * For conditions of distribution and use, see the accompanying README file. * * This file contains image transformation routines and other utility code * used by the jpegtran sample application. These are NOT part of the core * JPEG library. But we keep these routines separate from jpegtran.c to * ease the task of maintaining jpegtran-like programs that have other user * interfaces. */ /* Although this file really shouldn't have access to the library internals, * it's helpful to let it call jround_up() and jcopy_block_row(). */ #define JPEG_INTERNALS #include "jinclude.h" #include "jpeglib.h" #include "transupp.h" /* My own external interface */ #include /* to declare isdigit() */ #if TRANSFORMS_SUPPORTED /* * Lossless image transformation routines. These routines work on DCT * coefficient arrays and thus do not require any lossy decompression * or recompression of the image. * Thanks to Guido Vollbeding for the initial design and code of this feature, * and to Ben Jackson for introducing the cropping feature. * * Horizontal flipping is done in-place, using a single top-to-bottom * pass through the virtual source array. It will thus be much the * fastest option for images larger than main memory. * * The other routines require a set of destination virtual arrays, so they * need twice as much memory as jpegtran normally does. The destination * arrays are always written in normal scan order (top to bottom) because * the virtual array manager expects this. The source arrays will be scanned * in the corresponding order, which means multiple passes through the source * arrays for most of the transforms. That could result in much thrashing * if the image is larger than main memory. * * If cropping or trimming is involved, the destination arrays may be smaller * than the source arrays. Note it is not possible to do horizontal flip * in-place when a nonzero Y crop offset is specified, since we'd have to move * data from one block row to another but the virtual array manager doesn't * guarantee we can touch more than one row at a time. So in that case, * we have to use a separate destination array. * * Some notes about the operating environment of the individual transform * routines: * 1. Both the source and destination virtual arrays are allocated from the * source JPEG object, and therefore should be manipulated by calling the * source's memory manager. * 2. The destination's component count should be used. It may be smaller * than the source's when forcing to grayscale. * 3. Likewise the destination's sampling factors should be used. When * forcing to grayscale the destination's sampling factors will be all 1, * and we may as well take that as the effective iMCU size. * 4. When "trim" is in effect, the destination's dimensions will be the * trimmed values but the source's will be untrimmed. * 5. When "crop" is in effect, the destination's dimensions will be the * cropped values but the source's will be uncropped. Each transform * routine is responsible for picking up source data starting at the * correct X and Y offset for the crop region. (The X and Y offsets * passed to the transform routines are measured in iMCU blocks of the * destination.) * 6. All the routines assume that the source and destination buffers are * padded out to a full iMCU boundary. This is true, although for the * source buffer it is an undocumented property of jdcoefct.c. */ LOCAL(void) do_crop (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, jvirt_barray_ptr *src_coef_arrays, jvirt_barray_ptr *dst_coef_arrays) /* Crop. This is only used when no rotate/flip is requested with the crop. */ { JDIMENSION dst_blk_y, x_crop_blocks, y_crop_blocks; int ci, offset_y; JBLOCKARRAY src_buffer, dst_buffer; jpeg_component_info *compptr; /* We simply have to copy the right amount of data (the destination's * image size) starting at the given X and Y offsets in the source. */ for (ci = 0; ci < dstinfo->num_components; ci++) { compptr = dstinfo->comp_info + ci; x_crop_blocks = x_crop_offset * compptr->h_samp_factor; y_crop_blocks = y_crop_offset * compptr->v_samp_factor; for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; dst_blk_y += compptr->v_samp_factor) { dst_buffer = (*srcinfo->mem->access_virt_barray) ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y, (JDIMENSION) compptr->v_samp_factor, TRUE); src_buffer = (*srcinfo->mem->access_virt_barray) ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_y + y_crop_blocks, (JDIMENSION) compptr->v_samp_factor, FALSE); for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { jcopy_block_row(src_buffer[offset_y] + x_crop_blocks, dst_buffer[offset_y], compptr->width_in_blocks); } } } } LOCAL(void) do_crop_ext (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, jvirt_barray_ptr *src_coef_arrays, jvirt_barray_ptr *dst_coef_arrays) /* Crop. This is only used when no rotate/flip is requested with the crop. * Extension: If the destination size is larger than the source, we fill in * the extra area with zero (neutral gray). Note we also have to zero partial * iMCUs at the right and bottom edge of the source image area in this case. */ { JDIMENSION MCU_cols, MCU_rows, comp_width, comp_height; JDIMENSION dst_blk_y, x_crop_blocks, y_crop_blocks; int ci, offset_y; JBLOCKARRAY src_buffer, dst_buffer; jpeg_component_info *compptr; MCU_cols = srcinfo->output_width / (dstinfo->max_h_samp_factor * dstinfo->min_DCT_h_scaled_size); MCU_rows = srcinfo->output_height / (dstinfo->max_v_samp_factor * dstinfo->min_DCT_v_scaled_size); for (ci = 0; ci < dstinfo->num_components; ci++) { compptr = dstinfo->comp_info + ci; comp_width = MCU_cols * compptr->h_samp_factor; comp_height = MCU_rows * compptr->v_samp_factor; x_crop_blocks = x_crop_offset * compptr->h_samp_factor; y_crop_blocks = y_crop_offset * compptr->v_samp_factor; for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; dst_blk_y += compptr->v_samp_factor) { dst_buffer = (*srcinfo->mem->access_virt_barray) ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y, (JDIMENSION) compptr->v_samp_factor, TRUE); if (dstinfo->jpeg_height > srcinfo->output_height) { if (dst_blk_y < y_crop_blocks || dst_blk_y >= comp_height + y_crop_blocks) { for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { FMEMZERO(dst_buffer[offset_y], compptr->width_in_blocks * SIZEOF(JBLOCK)); } continue; } src_buffer = (*srcinfo->mem->access_virt_barray) ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_y - y_crop_blocks, (JDIMENSION) compptr->v_samp_factor, FALSE); } else { src_buffer = (*srcinfo->mem->access_virt_barray) ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_y + y_crop_blocks, (JDIMENSION) compptr->v_samp_factor, FALSE); } for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { if (dstinfo->jpeg_width > srcinfo->output_width) { if (x_crop_blocks > 0) { FMEMZERO(dst_buffer[offset_y], x_crop_blocks * SIZEOF(JBLOCK)); } jcopy_block_row(src_buffer[offset_y], dst_buffer[offset_y] + x_crop_blocks, comp_width); if (compptr->width_in_blocks > comp_width + x_crop_blocks) { FMEMZERO(dst_buffer[offset_y] + comp_width + x_crop_blocks, (compptr->width_in_blocks - comp_width - x_crop_blocks) * SIZEOF(JBLOCK)); } } else { jcopy_block_row(src_buffer[offset_y] + x_crop_blocks, dst_buffer[offset_y], compptr->width_in_blocks); } } } } } LOCAL(void) do_wipe (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, jvirt_barray_ptr *src_coef_arrays, JDIMENSION drop_width, JDIMENSION drop_height) /* Wipe - drop content of specified area, fill with zero (neutral gray) */ { JDIMENSION comp_width, comp_height; JDIMENSION blk_y, x_wipe_blocks, y_wipe_blocks; int ci, offset_y; JBLOCKARRAY buffer; jpeg_component_info *compptr; for (ci = 0; ci < dstinfo->num_components; ci++) { compptr = dstinfo->comp_info + ci; comp_width = drop_width * compptr->h_samp_factor; comp_height = drop_height * compptr->v_samp_factor; x_wipe_blocks = x_crop_offset * compptr->h_samp_factor; y_wipe_blocks = y_crop_offset * compptr->v_samp_factor; for (blk_y = 0; blk_y < comp_height; blk_y += compptr->v_samp_factor) { buffer = (*srcinfo->mem->access_virt_barray) ((j_common_ptr) srcinfo, src_coef_arrays[ci], blk_y + y_wipe_blocks, (JDIMENSION) compptr->v_samp_factor, TRUE); for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { FMEMZERO(buffer[offset_y] + x_wipe_blocks, comp_width * SIZEOF(JBLOCK)); } } } } LOCAL(void) do_flip_h_no_crop (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, JDIMENSION x_crop_offset, jvirt_barray_ptr *src_coef_arrays) /* Horizontal flip; done in-place, so no separate dest array is required. * NB: this only works when y_crop_offset is zero. */ { JDIMENSION MCU_cols, comp_width, blk_x, blk_y, x_crop_blocks; int ci, k, offset_y; JBLOCKARRAY buffer; JCOEFPTR ptr1, ptr2; JCOEF temp1, temp2; jpeg_component_info *compptr; /* Horizontal mirroring of DCT blocks is accomplished by swapping * pairs of blocks in-place. Within a DCT block, we perform horizontal * mirroring by changing the signs of odd-numbered columns. * Partial iMCUs at the right edge are left untouched. */ MCU_cols = srcinfo->output_width / (dstinfo->max_h_samp_factor * dstinfo->min_DCT_h_scaled_size); for (ci = 0; ci < dstinfo->num_components; ci++) { compptr = dstinfo->comp_info + ci; comp_width = MCU_cols * compptr->h_samp_factor; x_crop_blocks = x_crop_offset * compptr->h_samp_factor; for (blk_y = 0; blk_y < compptr->height_in_blocks; blk_y += compptr->v_samp_factor) { buffer = (*srcinfo->mem->access_virt_barray) ((j_common_ptr) srcinfo, src_coef_arrays[ci], blk_y, (JDIMENSION) compptr->v_samp_factor, TRUE); for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { /* Do the mirroring */ for (blk_x = 0; blk_x * 2 < comp_width; blk_x++) { ptr1 = buffer[offset_y][blk_x]; ptr2 = buffer[offset_y][comp_width - blk_x - 1]; /* this unrolled loop doesn't need to know which row it's on... */ for (k = 0; k < DCTSIZE2; k += 2) { temp1 = *ptr1; /* swap even column */ temp2 = *ptr2; *ptr1++ = temp2; *ptr2++ = temp1; temp1 = *ptr1; /* swap odd column with sign change */ temp2 = *ptr2; *ptr1++ = -temp2; *ptr2++ = -temp1; } } if (x_crop_blocks > 0) { /* Now left-justify the portion of the data to be kept. * We can't use a single jcopy_block_row() call because that routine * depends on memcpy(), whose behavior is unspecified for overlapping * source and destination areas. Sigh. */ for (blk_x = 0; blk_x < compptr->width_in_blocks; blk_x++) { jcopy_block_row(buffer[offset_y] + blk_x + x_crop_blocks, buffer[offset_y] + blk_x, (JDIMENSION) 1); } } } } } } LOCAL(void) do_flip_h (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, jvirt_barray_ptr *src_coef_arrays, jvirt_barray_ptr *dst_coef_arrays) /* Horizontal flip in general cropping case */ { JDIMENSION MCU_cols, comp_width, dst_blk_x, dst_blk_y; JDIMENSION x_crop_blocks, y_crop_blocks; int ci, k, offset_y; JBLOCKARRAY src_buffer, dst_buffer; JBLOCKROW src_row_ptr, dst_row_ptr; JCOEFPTR src_ptr, dst_ptr; jpeg_component_info *compptr; /* Here we must output into a separate array because we can't touch * different rows of a single virtual array simultaneously. Otherwise, * this is essentially the same as the routine above. */ MCU_cols = srcinfo->output_width / (dstinfo->max_h_samp_factor * dstinfo->min_DCT_h_scaled_size); for (ci = 0; ci < dstinfo->num_components; ci++) { compptr = dstinfo->comp_info + ci; comp_width = MCU_cols * compptr->h_samp_factor; x_crop_blocks = x_crop_offset * compptr->h_samp_factor; y_crop_blocks = y_crop_offset * compptr->v_samp_factor; for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; dst_blk_y += compptr->v_samp_factor) { dst_buffer = (*srcinfo->mem->access_virt_barray) ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y, (JDIMENSION) compptr->v_samp_factor, TRUE); src_buffer = (*srcinfo->mem->access_virt_barray) ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_y + y_crop_blocks, (JDIMENSION) compptr->v_samp_factor, FALSE); for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { dst_row_ptr = dst_buffer[offset_y]; src_row_ptr = src_buffer[offset_y]; for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; dst_blk_x++) { if (x_crop_blocks + dst_blk_x < comp_width) { /* Do the mirrorable blocks */ dst_ptr = dst_row_ptr[dst_blk_x]; src_ptr = src_row_ptr[comp_width - x_crop_blocks - dst_blk_x - 1]; /* this unrolled loop doesn't need to know which row it's on... */ for (k = 0; k < DCTSIZE2; k += 2) { *dst_ptr++ = *src_ptr++; /* copy even column */ *dst_ptr++ = - *src_ptr++; /* copy odd column with sign change */ } } else { /* Copy last partial block(s) verbatim */ jcopy_block_row(src_row_ptr + dst_blk_x + x_crop_blocks, dst_row_ptr + dst_blk_x, (JDIMENSION) 1); } } } } } } LOCAL(void) do_flip_v (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, jvirt_barray_ptr *src_coef_arrays, jvirt_barray_ptr *dst_coef_arrays) /* Vertical flip */ { JDIMENSION MCU_rows, comp_height, dst_blk_x, dst_blk_y; JDIMENSION x_crop_blocks, y_crop_blocks; int ci, i, j, offset_y; JBLOCKARRAY src_buffer, dst_buffer; JBLOCKROW src_row_ptr, dst_row_ptr; JCOEFPTR src_ptr, dst_ptr; jpeg_component_info *compptr; /* We output into a separate array because we can't touch different * rows of the source virtual array simultaneously. Otherwise, this * is a pretty straightforward analog of horizontal flip. * Within a DCT block, vertical mirroring is done by changing the signs * of odd-numbered rows. * Partial iMCUs at the bottom edge are copied verbatim. */ MCU_rows = srcinfo->output_height / (dstinfo->max_v_samp_factor * dstinfo->min_DCT_v_scaled_size); for (ci = 0; ci < dstinfo->num_components; ci++) { compptr = dstinfo->comp_info + ci; comp_height = MCU_rows * compptr->v_samp_factor; x_crop_blocks = x_crop_offset * compptr->h_samp_factor; y_crop_blocks = y_crop_offset * compptr->v_samp_factor; for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; dst_blk_y += compptr->v_samp_factor) { dst_buffer = (*srcinfo->mem->access_virt_barray) ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y, (JDIMENSION) compptr->v_samp_factor, TRUE); if (y_crop_blocks + dst_blk_y < comp_height) { /* Row is within the mirrorable area. */ src_buffer = (*srcinfo->mem->access_virt_barray) ((j_common_ptr) srcinfo, src_coef_arrays[ci], comp_height - y_crop_blocks - dst_blk_y - (JDIMENSION) compptr->v_samp_factor, (JDIMENSION) compptr->v_samp_factor, FALSE); } else { /* Bottom-edge blocks will be copied verbatim. */ src_buffer = (*srcinfo->mem->access_virt_barray) ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_y + y_crop_blocks, (JDIMENSION) compptr->v_samp_factor, FALSE); } for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { if (y_crop_blocks + dst_blk_y < comp_height) { /* Row is within the mirrorable area. */ dst_row_ptr = dst_buffer[offset_y]; src_row_ptr = src_buffer[compptr->v_samp_factor - offset_y - 1]; src_row_ptr += x_crop_blocks; for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; dst_blk_x++) { dst_ptr = dst_row_ptr[dst_blk_x]; src_ptr = src_row_ptr[dst_blk_x]; for (i = 0; i < DCTSIZE; i += 2) { /* copy even row */ for (j = 0; j < DCTSIZE; j++) *dst_ptr++ = *src_ptr++; /* copy odd row with sign change */ for (j = 0; j < DCTSIZE; j++) *dst_ptr++ = - *src_ptr++; } } } else { /* Just copy row verbatim. */ jcopy_block_row(src_buffer[offset_y] + x_crop_blocks, dst_buffer[offset_y], compptr->width_in_blocks); } } } } } LOCAL(void) do_transpose (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, jvirt_barray_ptr *src_coef_arrays, jvirt_barray_ptr *dst_coef_arrays) /* Transpose source into destination */ { JDIMENSION dst_blk_x, dst_blk_y, x_crop_blocks, y_crop_blocks; int ci, i, j, offset_x, offset_y; JBLOCKARRAY src_buffer, dst_buffer; JCOEFPTR src_ptr, dst_ptr; jpeg_component_info *compptr; /* Transposing pixels within a block just requires transposing the * DCT coefficients. * Partial iMCUs at the edges require no special treatment; we simply * process all the available DCT blocks for every component. */ for (ci = 0; ci < dstinfo->num_components; ci++) { compptr = dstinfo->comp_info + ci; x_crop_blocks = x_crop_offset * compptr->h_samp_factor; y_crop_blocks = y_crop_offset * compptr->v_samp_factor; for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; dst_blk_y += compptr->v_samp_factor) { dst_buffer = (*srcinfo->mem->access_virt_barray) ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y, (JDIMENSION) compptr->v_samp_factor, TRUE); for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; dst_blk_x += compptr->h_samp_factor) { src_buffer = (*srcinfo->mem->access_virt_barray) ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_x + x_crop_blocks, (JDIMENSION) compptr->h_samp_factor, FALSE); for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) { dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x]; src_ptr = src_buffer[offset_x][dst_blk_y + offset_y + y_crop_blocks]; for (i = 0; i < DCTSIZE; i++) for (j = 0; j < DCTSIZE; j++) dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; } } } } } } LOCAL(void) do_rot_90 (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, jvirt_barray_ptr *src_coef_arrays, jvirt_barray_ptr *dst_coef_arrays) /* 90 degree rotation is equivalent to * 1. Transposing the image; * 2. Horizontal mirroring. * These two steps are merged into a single processing routine. */ { JDIMENSION MCU_cols, comp_width, dst_blk_x, dst_blk_y; JDIMENSION x_crop_blocks, y_crop_blocks; int ci, i, j, offset_x, offset_y; JBLOCKARRAY src_buffer, dst_buffer; JCOEFPTR src_ptr, dst_ptr; jpeg_component_info *compptr; /* Because of the horizontal mirror step, we can't process partial iMCUs * at the (output) right edge properly. They just get transposed and * not mirrored. */ MCU_cols = srcinfo->output_height / (dstinfo->max_h_samp_factor * dstinfo->min_DCT_h_scaled_size); for (ci = 0; ci < dstinfo->num_components; ci++) { compptr = dstinfo->comp_info + ci; comp_width = MCU_cols * compptr->h_samp_factor; x_crop_blocks = x_crop_offset * compptr->h_samp_factor; y_crop_blocks = y_crop_offset * compptr->v_samp_factor; for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; dst_blk_y += compptr->v_samp_factor) { dst_buffer = (*srcinfo->mem->access_virt_barray) ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y, (JDIMENSION) compptr->v_samp_factor, TRUE); for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; dst_blk_x += compptr->h_samp_factor) { if (x_crop_blocks + dst_blk_x < comp_width) { /* Block is within the mirrorable area. */ src_buffer = (*srcinfo->mem->access_virt_barray) ((j_common_ptr) srcinfo, src_coef_arrays[ci], comp_width - x_crop_blocks - dst_blk_x - (JDIMENSION) compptr->h_samp_factor, (JDIMENSION) compptr->h_samp_factor, FALSE); } else { /* Edge blocks are transposed but not mirrored. */ src_buffer = (*srcinfo->mem->access_virt_barray) ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_x + x_crop_blocks, (JDIMENSION) compptr->h_samp_factor, FALSE); } for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) { dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x]; if (x_crop_blocks + dst_blk_x < comp_width) { /* Block is within the mirrorable area. */ src_ptr = src_buffer[compptr->h_samp_factor - offset_x - 1] [dst_blk_y + offset_y + y_crop_blocks]; for (i = 0; i < DCTSIZE; i++) { for (j = 0; j < DCTSIZE; j++) dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; i++; for (j = 0; j < DCTSIZE; j++) dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j]; } } else { /* Edge blocks are transposed but not mirrored. */ src_ptr = src_buffer[offset_x] [dst_blk_y + offset_y + y_crop_blocks]; for (i = 0; i < DCTSIZE; i++) for (j = 0; j < DCTSIZE; j++) dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; } } } } } } } LOCAL(void) do_rot_270 (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, jvirt_barray_ptr *src_coef_arrays, jvirt_barray_ptr *dst_coef_arrays) /* 270 degree rotation is equivalent to * 1. Horizontal mirroring; * 2. Transposing the image. * These two steps are merged into a single processing routine. */ { JDIMENSION MCU_rows, comp_height, dst_blk_x, dst_blk_y; JDIMENSION x_crop_blocks, y_crop_blocks; int ci, i, j, offset_x, offset_y; JBLOCKARRAY src_buffer, dst_buffer; JCOEFPTR src_ptr, dst_ptr; jpeg_component_info *compptr; /* Because of the horizontal mirror step, we can't process partial iMCUs * at the (output) bottom edge properly. They just get transposed and * not mirrored. */ MCU_rows = srcinfo->output_width / (dstinfo->max_v_samp_factor * dstinfo->min_DCT_v_scaled_size); for (ci = 0; ci < dstinfo->num_components; ci++) { compptr = dstinfo->comp_info + ci; comp_height = MCU_rows * compptr->v_samp_factor; x_crop_blocks = x_crop_offset * compptr->h_samp_factor; y_crop_blocks = y_crop_offset * compptr->v_samp_factor; for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; dst_blk_y += compptr->v_samp_factor) { dst_buffer = (*srcinfo->mem->access_virt_barray) ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y, (JDIMENSION) compptr->v_samp_factor, TRUE); for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; dst_blk_x += compptr->h_samp_factor) { src_buffer = (*srcinfo->mem->access_virt_barray) ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_x + x_crop_blocks, (JDIMENSION) compptr->h_samp_factor, FALSE); for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) { dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x]; if (y_crop_blocks + dst_blk_y < comp_height) { /* Block is within the mirrorable area. */ src_ptr = src_buffer[offset_x] [comp_height - y_crop_blocks - dst_blk_y - offset_y - 1]; for (i = 0; i < DCTSIZE; i++) { for (j = 0; j < DCTSIZE; j++) { dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; j++; dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j]; } } } else { /* Edge blocks are transposed but not mirrored. */ src_ptr = src_buffer[offset_x] [dst_blk_y + offset_y + y_crop_blocks]; for (i = 0; i < DCTSIZE; i++) for (j = 0; j < DCTSIZE; j++) dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; } } } } } } } LOCAL(void) do_rot_180 (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, jvirt_barray_ptr *src_coef_arrays, jvirt_barray_ptr *dst_coef_arrays) /* 180 degree rotation is equivalent to * 1. Vertical mirroring; * 2. Horizontal mirroring. * These two steps are merged into a single processing routine. */ { JDIMENSION MCU_cols, MCU_rows, comp_width, comp_height, dst_blk_x, dst_blk_y; JDIMENSION x_crop_blocks, y_crop_blocks; int ci, i, j, offset_y; JBLOCKARRAY src_buffer, dst_buffer; JBLOCKROW src_row_ptr, dst_row_ptr; JCOEFPTR src_ptr, dst_ptr; jpeg_component_info *compptr; MCU_cols = srcinfo->output_width / (dstinfo->max_h_samp_factor * dstinfo->min_DCT_h_scaled_size); MCU_rows = srcinfo->output_height / (dstinfo->max_v_samp_factor * dstinfo->min_DCT_v_scaled_size); for (ci = 0; ci < dstinfo->num_components; ci++) { compptr = dstinfo->comp_info + ci; comp_width = MCU_cols * compptr->h_samp_factor; comp_height = MCU_rows * compptr->v_samp_factor; x_crop_blocks = x_crop_offset * compptr->h_samp_factor; y_crop_blocks = y_crop_offset * compptr->v_samp_factor; for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; dst_blk_y += compptr->v_samp_factor) { dst_buffer = (*srcinfo->mem->access_virt_barray) ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y, (JDIMENSION) compptr->v_samp_factor, TRUE); if (y_crop_blocks + dst_blk_y < comp_height) { /* Row is within the vertically mirrorable area. */ src_buffer = (*srcinfo->mem->access_virt_barray) ((j_common_ptr) srcinfo, src_coef_arrays[ci], comp_height - y_crop_blocks - dst_blk_y - (JDIMENSION) compptr->v_samp_factor, (JDIMENSION) compptr->v_samp_factor, FALSE); } else { /* Bottom-edge rows are only mirrored horizontally. */ src_buffer = (*srcinfo->mem->access_virt_barray) ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_y + y_crop_blocks, (JDIMENSION) compptr->v_samp_factor, FALSE); } for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { dst_row_ptr = dst_buffer[offset_y]; if (y_crop_blocks + dst_blk_y < comp_height) { /* Row is within the mirrorable area. */ src_row_ptr = src_buffer[compptr->v_samp_factor - offset_y - 1]; for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; dst_blk_x++) { dst_ptr = dst_row_ptr[dst_blk_x]; if (x_crop_blocks + dst_blk_x < comp_width) { /* Process the blocks that can be mirrored both ways. */ src_ptr = src_row_ptr[comp_width - x_crop_blocks - dst_blk_x - 1]; for (i = 0; i < DCTSIZE; i += 2) { /* For even row, negate every odd column. */ for (j = 0; j < DCTSIZE; j += 2) { *dst_ptr++ = *src_ptr++; *dst_ptr++ = - *src_ptr++; } /* For odd row, negate every even column. */ for (j = 0; j < DCTSIZE; j += 2) { *dst_ptr++ = - *src_ptr++; *dst_ptr++ = *src_ptr++; } } } else { /* Any remaining right-edge blocks are only mirrored vertically. */ src_ptr = src_row_ptr[x_crop_blocks + dst_blk_x]; for (i = 0; i < DCTSIZE; i += 2) { for (j = 0; j < DCTSIZE; j++) *dst_ptr++ = *src_ptr++; for (j = 0; j < DCTSIZE; j++) *dst_ptr++ = - *src_ptr++; } } } } else { /* Remaining rows are just mirrored horizontally. */ src_row_ptr = src_buffer[offset_y]; for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; dst_blk_x++) { if (x_crop_blocks + dst_blk_x < comp_width) { /* Process the blocks that can be mirrored. */ dst_ptr = dst_row_ptr[dst_blk_x]; src_ptr = src_row_ptr[comp_width - x_crop_blocks - dst_blk_x - 1]; for (i = 0; i < DCTSIZE2; i += 2) { *dst_ptr++ = *src_ptr++; *dst_ptr++ = - *src_ptr++; } } else { /* Any remaining right-edge blocks are only copied. */ jcopy_block_row(src_row_ptr + dst_blk_x + x_crop_blocks, dst_row_ptr + dst_blk_x, (JDIMENSION) 1); } } } } } } } LOCAL(void) do_transverse (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, jvirt_barray_ptr *src_coef_arrays, jvirt_barray_ptr *dst_coef_arrays) /* Transverse transpose is equivalent to * 1. 180 degree rotation; * 2. Transposition; * or * 1. Horizontal mirroring; * 2. Transposition; * 3. Horizontal mirroring. * These steps are merged into a single processing routine. */ { JDIMENSION MCU_cols, MCU_rows, comp_width, comp_height, dst_blk_x, dst_blk_y; JDIMENSION x_crop_blocks, y_crop_blocks; int ci, i, j, offset_x, offset_y; JBLOCKARRAY src_buffer, dst_buffer; JCOEFPTR src_ptr, dst_ptr; jpeg_component_info *compptr; MCU_cols = srcinfo->output_height / (dstinfo->max_h_samp_factor * dstinfo->min_DCT_h_scaled_size); MCU_rows = srcinfo->output_width / (dstinfo->max_v_samp_factor * dstinfo->min_DCT_v_scaled_size); for (ci = 0; ci < dstinfo->num_components; ci++) { compptr = dstinfo->comp_info + ci; comp_width = MCU_cols * compptr->h_samp_factor; comp_height = MCU_rows * compptr->v_samp_factor; x_crop_blocks = x_crop_offset * compptr->h_samp_factor; y_crop_blocks = y_crop_offset * compptr->v_samp_factor; for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; dst_blk_y += compptr->v_samp_factor) { dst_buffer = (*srcinfo->mem->access_virt_barray) ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y, (JDIMENSION) compptr->v_samp_factor, TRUE); for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; dst_blk_x += compptr->h_samp_factor) { if (x_crop_blocks + dst_blk_x < comp_width) { /* Block is within the mirrorable area. */ src_buffer = (*srcinfo->mem->access_virt_barray) ((j_common_ptr) srcinfo, src_coef_arrays[ci], comp_width - x_crop_blocks - dst_blk_x - (JDIMENSION) compptr->h_samp_factor, (JDIMENSION) compptr->h_samp_factor, FALSE); } else { src_buffer = (*srcinfo->mem->access_virt_barray) ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_x + x_crop_blocks, (JDIMENSION) compptr->h_samp_factor, FALSE); } for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) { dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x]; if (y_crop_blocks + dst_blk_y < comp_height) { if (x_crop_blocks + dst_blk_x < comp_width) { /* Block is within the mirrorable area. */ src_ptr = src_buffer[compptr->h_samp_factor - offset_x - 1] [comp_height - y_crop_blocks - dst_blk_y - offset_y - 1]; for (i = 0; i < DCTSIZE; i++) { for (j = 0; j < DCTSIZE; j++) { dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; j++; dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j]; } i++; for (j = 0; j < DCTSIZE; j++) { dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j]; j++; dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; } } } else { /* Right-edge blocks are mirrored in y only */ src_ptr = src_buffer[offset_x] [comp_height - y_crop_blocks - dst_blk_y - offset_y - 1]; for (i = 0; i < DCTSIZE; i++) { for (j = 0; j < DCTSIZE; j++) { dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; j++; dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j]; } } } } else { if (x_crop_blocks + dst_blk_x < comp_width) { /* Bottom-edge blocks are mirrored in x only */ src_ptr = src_buffer[compptr->h_samp_factor - offset_x - 1] [dst_blk_y + offset_y + y_crop_blocks]; for (i = 0; i < DCTSIZE; i++) { for (j = 0; j < DCTSIZE; j++) dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; i++; for (j = 0; j < DCTSIZE; j++) dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j]; } } else { /* At lower right corner, just transpose, no mirroring */ src_ptr = src_buffer[offset_x] [dst_blk_y + offset_y + y_crop_blocks]; for (i = 0; i < DCTSIZE; i++) for (j = 0; j < DCTSIZE; j++) dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; } } } } } } } } /* Parse an unsigned integer: subroutine for jtransform_parse_crop_spec. * Returns TRUE if valid integer found, FALSE if not. * *strptr is advanced over the digit string, and *result is set to its value. */ LOCAL(boolean) jt_read_integer (const char ** strptr, JDIMENSION * result) { const char * ptr = *strptr; JDIMENSION val = 0; for (; isdigit(*ptr); ptr++) { val = val * 10 + (JDIMENSION) (*ptr - '0'); } *result = val; if (ptr == *strptr) return FALSE; /* oops, no digits */ *strptr = ptr; return TRUE; } /* Parse a crop specification (written in X11 geometry style). * The routine returns TRUE if the spec string is valid, FALSE if not. * * The crop spec string should have the format * [f]x[f]{+-}{+-} * where width, height, xoffset, and yoffset are unsigned integers. * Each of the elements can be omitted to indicate a default value. * (A weakness of this style is that it is not possible to omit xoffset * while specifying yoffset, since they look alike.) * * This code is loosely based on XParseGeometry from the X11 distribution. */ GLOBAL(boolean) jtransform_parse_crop_spec (jpeg_transform_info *info, const char *spec) { info->crop = FALSE; info->crop_width_set = JCROP_UNSET; info->crop_height_set = JCROP_UNSET; info->crop_xoffset_set = JCROP_UNSET; info->crop_yoffset_set = JCROP_UNSET; if (isdigit(*spec)) { /* fetch width */ if (! jt_read_integer(&spec, &info->crop_width)) return FALSE; if (*spec == 'f' || *spec == 'F') { spec++; info->crop_width_set = JCROP_FORCE; } else info->crop_width_set = JCROP_POS; } if (*spec == 'x' || *spec == 'X') { /* fetch height */ spec++; if (! jt_read_integer(&spec, &info->crop_height)) return FALSE; if (*spec == 'f' || *spec == 'F') { spec++; info->crop_height_set = JCROP_FORCE; } else info->crop_height_set = JCROP_POS; } if (*spec == '+' || *spec == '-') { /* fetch xoffset */ info->crop_xoffset_set = (*spec == '-') ? JCROP_NEG : JCROP_POS; spec++; if (! jt_read_integer(&spec, &info->crop_xoffset)) return FALSE; } if (*spec == '+' || *spec == '-') { /* fetch yoffset */ info->crop_yoffset_set = (*spec == '-') ? JCROP_NEG : JCROP_POS; spec++; if (! jt_read_integer(&spec, &info->crop_yoffset)) return FALSE; } /* We had better have gotten to the end of the string. */ if (*spec != '\0') return FALSE; info->crop = TRUE; return TRUE; } /* Trim off any partial iMCUs on the indicated destination edge */ LOCAL(void) trim_right_edge (jpeg_transform_info *info, JDIMENSION full_width) { JDIMENSION MCU_cols; MCU_cols = info->output_width / info->iMCU_sample_width; if (MCU_cols > 0 && info->x_crop_offset + MCU_cols == full_width / info->iMCU_sample_width) info->output_width = MCU_cols * info->iMCU_sample_width; } LOCAL(void) trim_bottom_edge (jpeg_transform_info *info, JDIMENSION full_height) { JDIMENSION MCU_rows; MCU_rows = info->output_height / info->iMCU_sample_height; if (MCU_rows > 0 && info->y_crop_offset + MCU_rows == full_height / info->iMCU_sample_height) info->output_height = MCU_rows * info->iMCU_sample_height; } /* Request any required workspace. * * This routine figures out the size that the output image will be * (which implies that all the transform parameters must be set before * it is called). * * We allocate the workspace virtual arrays from the source decompression * object, so that all the arrays (both the original data and the workspace) * will be taken into account while making memory management decisions. * Hence, this routine must be called after jpeg_read_header (which reads * the image dimensions) and before jpeg_read_coefficients (which realizes * the source's virtual arrays). * * This function returns FALSE right away if -perfect is given * and transformation is not perfect. Otherwise returns TRUE. */ GLOBAL(boolean) jtransform_request_workspace (j_decompress_ptr srcinfo, jpeg_transform_info *info) { jvirt_barray_ptr *coef_arrays; boolean need_workspace, transpose_it; jpeg_component_info *compptr; JDIMENSION xoffset, yoffset; JDIMENSION width_in_iMCUs, height_in_iMCUs; JDIMENSION width_in_blocks, height_in_blocks; int ci, h_samp_factor, v_samp_factor; /* Determine number of components in output image */ if (info->force_grayscale && (srcinfo->jpeg_color_space == JCS_YCbCr || srcinfo->jpeg_color_space == JCS_BG_YCC) && srcinfo->num_components == 3) /* We'll only process the first component */ info->num_components = 1; else /* Process all the components */ info->num_components = srcinfo->num_components; /* Compute output image dimensions and related values. */ jpeg_core_output_dimensions(srcinfo); /* Return right away if -perfect is given and transformation is not perfect. */ if (info->perfect) { if (info->num_components == 1) { if (!jtransform_perfect_transform(srcinfo->output_width, srcinfo->output_height, srcinfo->min_DCT_h_scaled_size, srcinfo->min_DCT_v_scaled_size, info->transform)) return FALSE; } else { if (!jtransform_perfect_transform(srcinfo->output_width, srcinfo->output_height, srcinfo->max_h_samp_factor * srcinfo->min_DCT_h_scaled_size, srcinfo->max_v_samp_factor * srcinfo->min_DCT_v_scaled_size, info->transform)) return FALSE; } } /* If there is only one output component, force the iMCU size to be 1; * else use the source iMCU size. (This allows us to do the right thing * when reducing color to grayscale, and also provides a handy way of * cleaning up "funny" grayscale images whose sampling factors are not 1x1.) */ switch (info->transform) { case JXFORM_TRANSPOSE: case JXFORM_TRANSVERSE: case JXFORM_ROT_90: case JXFORM_ROT_270: info->output_width = srcinfo->output_height; info->output_height = srcinfo->output_width; if (info->num_components == 1) { info->iMCU_sample_width = srcinfo->min_DCT_v_scaled_size; info->iMCU_sample_height = srcinfo->min_DCT_h_scaled_size; } else { info->iMCU_sample_width = srcinfo->max_v_samp_factor * srcinfo->min_DCT_v_scaled_size; info->iMCU_sample_height = srcinfo->max_h_samp_factor * srcinfo->min_DCT_h_scaled_size; } break; default: info->output_width = srcinfo->output_width; info->output_height = srcinfo->output_height; if (info->num_components == 1) { info->iMCU_sample_width = srcinfo->min_DCT_h_scaled_size; info->iMCU_sample_height = srcinfo->min_DCT_v_scaled_size; } else { info->iMCU_sample_width = srcinfo->max_h_samp_factor * srcinfo->min_DCT_h_scaled_size; info->iMCU_sample_height = srcinfo->max_v_samp_factor * srcinfo->min_DCT_v_scaled_size; } break; } /* If cropping has been requested, compute the crop area's position and * dimensions, ensuring that its upper left corner falls at an iMCU boundary. */ if (info->crop) { /* Insert default values for unset crop parameters */ if (info->crop_xoffset_set == JCROP_UNSET) info->crop_xoffset = 0; /* default to +0 */ if (info->crop_yoffset_set == JCROP_UNSET) info->crop_yoffset = 0; /* default to +0 */ if (info->crop_width_set == JCROP_UNSET) { if (info->crop_xoffset >= info->output_width) ERREXIT(srcinfo, JERR_BAD_CROP_SPEC); info->crop_width = info->output_width - info->crop_xoffset; } else { /* Check for crop extension */ if (info->crop_width > info->output_width) { /* Crop extension does not work when transforming! */ if (info->transform != JXFORM_NONE || info->crop_xoffset >= info->crop_width || info->crop_xoffset > info->crop_width - info->output_width) ERREXIT(srcinfo, JERR_BAD_CROP_SPEC); } else { if (info->crop_xoffset >= info->output_width || info->crop_width <= 0 || info->crop_xoffset > info->output_width - info->crop_width) ERREXIT(srcinfo, JERR_BAD_CROP_SPEC); } } if (info->crop_height_set == JCROP_UNSET) { if (info->crop_yoffset >= info->output_height) ERREXIT(srcinfo, JERR_BAD_CROP_SPEC); info->crop_height = info->output_height - info->crop_yoffset; } else { /* Check for crop extension */ if (info->crop_height > info->output_height) { /* Crop extension does not work when transforming! */ if (info->transform != JXFORM_NONE || info->crop_yoffset >= info->crop_height || info->crop_yoffset > info->crop_height - info->output_height) ERREXIT(srcinfo, JERR_BAD_CROP_SPEC); } else { if (info->crop_yoffset >= info->output_height || info->crop_height <= 0 || info->crop_yoffset > info->output_height - info->crop_height) ERREXIT(srcinfo, JERR_BAD_CROP_SPEC); } } /* Convert negative crop offsets into regular offsets */ if (info->crop_xoffset_set != JCROP_NEG) xoffset = info->crop_xoffset; else if (info->crop_width > info->output_width) /* crop extension */ xoffset = info->crop_width - info->output_width - info->crop_xoffset; else xoffset = info->output_width - info->crop_width - info->crop_xoffset; if (info->crop_yoffset_set != JCROP_NEG) yoffset = info->crop_yoffset; else if (info->crop_height > info->output_height) /* crop extension */ yoffset = info->crop_height - info->output_height - info->crop_yoffset; else yoffset = info->output_height - info->crop_height - info->crop_yoffset; /* Now adjust so that upper left corner falls at an iMCU boundary */ if (info->transform == JXFORM_WIPE) { /* Ensure the effective wipe region will cover the requested */ info->drop_width = (JDIMENSION) jdiv_round_up ((long) (info->crop_width + (xoffset % info->iMCU_sample_width)), (long) info->iMCU_sample_width); info->drop_height = (JDIMENSION) jdiv_round_up ((long) (info->crop_height + (yoffset % info->iMCU_sample_height)), (long) info->iMCU_sample_height); } else { /* Ensure the effective crop region will cover the requested */ if (info->crop_width_set == JCROP_FORCE || info->crop_width > info->output_width) info->output_width = info->crop_width; else info->output_width = info->crop_width + (xoffset % info->iMCU_sample_width); if (info->crop_height_set == JCROP_FORCE || info->crop_height > info->output_height) info->output_height = info->crop_height; else info->output_height = info->crop_height + (yoffset % info->iMCU_sample_height); } /* Save x/y offsets measured in iMCUs */ info->x_crop_offset = xoffset / info->iMCU_sample_width; info->y_crop_offset = yoffset / info->iMCU_sample_height; } else { info->x_crop_offset = 0; info->y_crop_offset = 0; } /* Figure out whether we need workspace arrays, * and if so whether they are transposed relative to the source. */ need_workspace = FALSE; transpose_it = FALSE; switch (info->transform) { case JXFORM_NONE: if (info->x_crop_offset != 0 || info->y_crop_offset != 0 || info->output_width > srcinfo->output_width || info->output_height > srcinfo->output_height) need_workspace = TRUE; /* No workspace needed if neither cropping nor transforming */ break; case JXFORM_FLIP_H: if (info->trim) trim_right_edge(info, srcinfo->output_width); if (info->y_crop_offset != 0) need_workspace = TRUE; /* do_flip_h_no_crop doesn't need a workspace array */ break; case JXFORM_FLIP_V: if (info->trim) trim_bottom_edge(info, srcinfo->output_height); /* Need workspace arrays having same dimensions as source image. */ need_workspace = TRUE; break; case JXFORM_TRANSPOSE: /* transpose does NOT have to trim anything */ /* Need workspace arrays having transposed dimensions. */ need_workspace = TRUE; transpose_it = TRUE; break; case JXFORM_TRANSVERSE: if (info->trim) { trim_right_edge(info, srcinfo->output_height); trim_bottom_edge(info, srcinfo->output_width); } /* Need workspace arrays having transposed dimensions. */ need_workspace = TRUE; transpose_it = TRUE; break; case JXFORM_ROT_90: if (info->trim) trim_right_edge(info, srcinfo->output_height); /* Need workspace arrays having transposed dimensions. */ need_workspace = TRUE; transpose_it = TRUE; break; case JXFORM_ROT_180: if (info->trim) { trim_right_edge(info, srcinfo->output_width); trim_bottom_edge(info, srcinfo->output_height); } /* Need workspace arrays having same dimensions as source image. */ need_workspace = TRUE; break; case JXFORM_ROT_270: if (info->trim) trim_bottom_edge(info, srcinfo->output_width); /* Need workspace arrays having transposed dimensions. */ need_workspace = TRUE; transpose_it = TRUE; break; case JXFORM_WIPE: break; } /* Allocate workspace if needed. * Note that we allocate arrays padded out to the next iMCU boundary, * so that transform routines need not worry about missing edge blocks. */ if (need_workspace) { coef_arrays = (jvirt_barray_ptr *) (*srcinfo->mem->alloc_small) ((j_common_ptr) srcinfo, JPOOL_IMAGE, SIZEOF(jvirt_barray_ptr) * info->num_components); width_in_iMCUs = (JDIMENSION) jdiv_round_up((long) info->output_width, (long) info->iMCU_sample_width); height_in_iMCUs = (JDIMENSION) jdiv_round_up((long) info->output_height, (long) info->iMCU_sample_height); for (ci = 0; ci < info->num_components; ci++) { compptr = srcinfo->comp_info + ci; if (info->num_components == 1) { /* we're going to force samp factors to 1x1 in this case */ h_samp_factor = v_samp_factor = 1; } else if (transpose_it) { h_samp_factor = compptr->v_samp_factor; v_samp_factor = compptr->h_samp_factor; } else { h_samp_factor = compptr->h_samp_factor; v_samp_factor = compptr->v_samp_factor; } width_in_blocks = width_in_iMCUs * h_samp_factor; height_in_blocks = height_in_iMCUs * v_samp_factor; coef_arrays[ci] = (*srcinfo->mem->request_virt_barray) ((j_common_ptr) srcinfo, JPOOL_IMAGE, FALSE, width_in_blocks, height_in_blocks, (JDIMENSION) v_samp_factor); } info->workspace_coef_arrays = coef_arrays; } else info->workspace_coef_arrays = NULL; return TRUE; } /* Transpose destination image parameters */ LOCAL(void) transpose_critical_parameters (j_compress_ptr dstinfo) { int tblno, i, j, ci, itemp; jpeg_component_info *compptr; JQUANT_TBL *qtblptr; JDIMENSION jtemp; UINT16 qtemp; /* Transpose image dimensions */ jtemp = dstinfo->image_width; dstinfo->image_width = dstinfo->image_height; dstinfo->image_height = jtemp; itemp = dstinfo->min_DCT_h_scaled_size; dstinfo->min_DCT_h_scaled_size = dstinfo->min_DCT_v_scaled_size; dstinfo->min_DCT_v_scaled_size = itemp; /* Transpose sampling factors */ for (ci = 0; ci < dstinfo->num_components; ci++) { compptr = dstinfo->comp_info + ci; itemp = compptr->h_samp_factor; compptr->h_samp_factor = compptr->v_samp_factor; compptr->v_samp_factor = itemp; } /* Transpose quantization tables */ for (tblno = 0; tblno < NUM_QUANT_TBLS; tblno++) { qtblptr = dstinfo->quant_tbl_ptrs[tblno]; if (qtblptr != NULL) { for (i = 0; i < DCTSIZE; i++) { for (j = 0; j < i; j++) { qtemp = qtblptr->quantval[i*DCTSIZE+j]; qtblptr->quantval[i*DCTSIZE+j] = qtblptr->quantval[j*DCTSIZE+i]; qtblptr->quantval[j*DCTSIZE+i] = qtemp; } } } } } /* Adjust Exif image parameters. * * We try to adjust the Tags ExifImageWidth and ExifImageHeight if possible. */ LOCAL(void) adjust_exif_parameters (JOCTET FAR * data, unsigned int length, JDIMENSION new_width, JDIMENSION new_height) { boolean is_motorola; /* Flag for byte order */ unsigned int number_of_tags, tagnum; unsigned int firstoffset, offset; JDIMENSION new_value; if (length < 12) return; /* Length of an IFD entry */ /* Discover byte order */ if (GETJOCTET(data[0]) == 0x49 && GETJOCTET(data[1]) == 0x49) is_motorola = FALSE; else if (GETJOCTET(data[0]) == 0x4D && GETJOCTET(data[1]) == 0x4D) is_motorola = TRUE; else return; /* Check Tag Mark */ if (is_motorola) { if (GETJOCTET(data[2]) != 0) return; if (GETJOCTET(data[3]) != 0x2A) return; } else { if (GETJOCTET(data[3]) != 0) return; if (GETJOCTET(data[2]) != 0x2A) return; } /* Get first IFD offset (offset to IFD0) */ if (is_motorola) { if (GETJOCTET(data[4]) != 0) return; if (GETJOCTET(data[5]) != 0) return; firstoffset = GETJOCTET(data[6]); firstoffset <<= 8; firstoffset += GETJOCTET(data[7]); } else { if (GETJOCTET(data[7]) != 0) return; if (GETJOCTET(data[6]) != 0) return; firstoffset = GETJOCTET(data[5]); firstoffset <<= 8; firstoffset += GETJOCTET(data[4]); } if (firstoffset > length - 2) return; /* check end of data segment */ /* Get the number of directory entries contained in this IFD */ if (is_motorola) { number_of_tags = GETJOCTET(data[firstoffset]); number_of_tags <<= 8; number_of_tags += GETJOCTET(data[firstoffset+1]); } else { number_of_tags = GETJOCTET(data[firstoffset+1]); number_of_tags <<= 8; number_of_tags += GETJOCTET(data[firstoffset]); } if (number_of_tags == 0) return; firstoffset += 2; /* Search for ExifSubIFD offset Tag in IFD0 */ for (;;) { if (firstoffset > length - 12) return; /* check end of data segment */ /* Get Tag number */ if (is_motorola) { tagnum = GETJOCTET(data[firstoffset]); tagnum <<= 8; tagnum += GETJOCTET(data[firstoffset+1]); } else { tagnum = GETJOCTET(data[firstoffset+1]); tagnum <<= 8; tagnum += GETJOCTET(data[firstoffset]); } if (tagnum == 0x8769) break; /* found ExifSubIFD offset Tag */ if (--number_of_tags == 0) return; firstoffset += 12; } /* Get the ExifSubIFD offset */ if (is_motorola) { if (GETJOCTET(data[firstoffset+8]) != 0) return; if (GETJOCTET(data[firstoffset+9]) != 0) return; offset = GETJOCTET(data[firstoffset+10]); offset <<= 8; offset += GETJOCTET(data[firstoffset+11]); } else { if (GETJOCTET(data[firstoffset+11]) != 0) return; if (GETJOCTET(data[firstoffset+10]) != 0) return; offset = GETJOCTET(data[firstoffset+9]); offset <<= 8; offset += GETJOCTET(data[firstoffset+8]); } if (offset > length - 2) return; /* check end of data segment */ /* Get the number of directory entries contained in this SubIFD */ if (is_motorola) { number_of_tags = GETJOCTET(data[offset]); number_of_tags <<= 8; number_of_tags += GETJOCTET(data[offset+1]); } else { number_of_tags = GETJOCTET(data[offset+1]); number_of_tags <<= 8; number_of_tags += GETJOCTET(data[offset]); } if (number_of_tags < 2) return; offset += 2; /* Search for ExifImageWidth and ExifImageHeight Tags in this SubIFD */ do { if (offset > length - 12) return; /* check end of data segment */ /* Get Tag number */ if (is_motorola) { tagnum = GETJOCTET(data[offset]); tagnum <<= 8; tagnum += GETJOCTET(data[offset+1]); } else { tagnum = GETJOCTET(data[offset+1]); tagnum <<= 8; tagnum += GETJOCTET(data[offset]); } if (tagnum == 0xA002 || tagnum == 0xA003) { if (tagnum == 0xA002) new_value = new_width; /* ExifImageWidth Tag */ else new_value = new_height; /* ExifImageHeight Tag */ if (is_motorola) { data[offset+2] = 0; /* Format = unsigned long (4 octets) */ data[offset+3] = 4; data[offset+4] = 0; /* Number Of Components = 1 */ data[offset+5] = 0; data[offset+6] = 0; data[offset+7] = 1; data[offset+8] = 0; data[offset+9] = 0; data[offset+10] = (JOCTET)((new_value >> 8) & 0xFF); data[offset+11] = (JOCTET)(new_value & 0xFF); } else { data[offset+2] = 4; /* Format = unsigned long (4 octets) */ data[offset+3] = 0; data[offset+4] = 1; /* Number Of Components = 1 */ data[offset+5] = 0; data[offset+6] = 0; data[offset+7] = 0; data[offset+8] = (JOCTET)(new_value & 0xFF); data[offset+9] = (JOCTET)((new_value >> 8) & 0xFF); data[offset+10] = 0; data[offset+11] = 0; } } offset += 12; } while (--number_of_tags); } /* Adjust output image parameters as needed. * * This must be called after jpeg_copy_critical_parameters() * and before jpeg_write_coefficients(). * * The return value is the set of virtual coefficient arrays to be written * (either the ones allocated by jtransform_request_workspace, or the * original source data arrays). The caller will need to pass this value * to jpeg_write_coefficients(). */ GLOBAL(jvirt_barray_ptr *) jtransform_adjust_parameters (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, jvirt_barray_ptr *src_coef_arrays, jpeg_transform_info *info) { /* If force-to-grayscale is requested, adjust destination parameters */ if (info->force_grayscale) { /* First, ensure we have YCC or grayscale data, and that the source's * Y channel is full resolution. (No reasonable person would make Y * be less than full resolution, so actually coping with that case * isn't worth extra code space. But we check it to avoid crashing.) */ if ((((dstinfo->jpeg_color_space == JCS_YCbCr || dstinfo->jpeg_color_space == JCS_BG_YCC) && dstinfo->num_components == 3) || (dstinfo->jpeg_color_space == JCS_GRAYSCALE && dstinfo->num_components == 1)) && srcinfo->comp_info[0].h_samp_factor == srcinfo->max_h_samp_factor && srcinfo->comp_info[0].v_samp_factor == srcinfo->max_v_samp_factor) { /* We use jpeg_set_colorspace to make sure subsidiary settings get fixed * properly. Among other things, it sets the target h_samp_factor & * v_samp_factor to 1, which typically won't match the source. * We have to preserve the source's quantization table number, however. */ int sv_quant_tbl_no = dstinfo->comp_info[0].quant_tbl_no; jpeg_set_colorspace(dstinfo, JCS_GRAYSCALE); dstinfo->comp_info[0].quant_tbl_no = sv_quant_tbl_no; } else { /* Sorry, can't do it */ ERREXIT(dstinfo, JERR_CONVERSION_NOTIMPL); } } else if (info->num_components == 1) { /* For a single-component source, we force the destination sampling factors * to 1x1, with or without force_grayscale. This is useful because some * decoders choke on grayscale images with other sampling factors. */ dstinfo->comp_info[0].h_samp_factor = 1; dstinfo->comp_info[0].v_samp_factor = 1; } /* Correct the destination's image dimensions as necessary * for rotate/flip, resize, and crop operations. */ dstinfo->jpeg_width = info->output_width; dstinfo->jpeg_height = info->output_height; /* Transpose destination image parameters */ switch (info->transform) { case JXFORM_TRANSPOSE: case JXFORM_TRANSVERSE: case JXFORM_ROT_90: case JXFORM_ROT_270: transpose_critical_parameters(dstinfo); break; default: break; } /* Adjust Exif properties */ if (srcinfo->marker_list != NULL && srcinfo->marker_list->marker == JPEG_APP0+1 && srcinfo->marker_list->data_length >= 6 && GETJOCTET(srcinfo->marker_list->data[0]) == 0x45 && GETJOCTET(srcinfo->marker_list->data[1]) == 0x78 && GETJOCTET(srcinfo->marker_list->data[2]) == 0x69 && GETJOCTET(srcinfo->marker_list->data[3]) == 0x66 && GETJOCTET(srcinfo->marker_list->data[4]) == 0 && GETJOCTET(srcinfo->marker_list->data[5]) == 0) { /* Suppress output of JFIF marker */ dstinfo->write_JFIF_header = FALSE; /* Adjust Exif image parameters */ if (dstinfo->jpeg_width != srcinfo->image_width || dstinfo->jpeg_height != srcinfo->image_height) /* Align data segment to start of TIFF structure for parsing */ adjust_exif_parameters(srcinfo->marker_list->data + 6, srcinfo->marker_list->data_length - 6, dstinfo->jpeg_width, dstinfo->jpeg_height); } /* Return the appropriate output data set */ if (info->workspace_coef_arrays != NULL) return info->workspace_coef_arrays; return src_coef_arrays; } /* Execute the actual transformation, if any. * * This must be called *after* jpeg_write_coefficients, because it depends * on jpeg_write_coefficients to have computed subsidiary values such as * the per-component width and height fields in the destination object. * * Note that some transformations will modify the source data arrays! */ GLOBAL(void) jtransform_execute_transform (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, jvirt_barray_ptr *src_coef_arrays, jpeg_transform_info *info) { jvirt_barray_ptr *dst_coef_arrays = info->workspace_coef_arrays; /* Note: conditions tested here should match those in switch statement * in jtransform_request_workspace() */ switch (info->transform) { case JXFORM_NONE: if (info->output_width > srcinfo->output_width || info->output_height > srcinfo->output_height) do_crop_ext(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset, src_coef_arrays, dst_coef_arrays); else if (info->x_crop_offset != 0 || info->y_crop_offset != 0) do_crop(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset, src_coef_arrays, dst_coef_arrays); break; case JXFORM_FLIP_H: if (info->y_crop_offset != 0) do_flip_h(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset, src_coef_arrays, dst_coef_arrays); else do_flip_h_no_crop(srcinfo, dstinfo, info->x_crop_offset, src_coef_arrays); break; case JXFORM_FLIP_V: do_flip_v(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset, src_coef_arrays, dst_coef_arrays); break; case JXFORM_TRANSPOSE: do_transpose(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset, src_coef_arrays, dst_coef_arrays); break; case JXFORM_TRANSVERSE: do_transverse(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset, src_coef_arrays, dst_coef_arrays); break; case JXFORM_ROT_90: do_rot_90(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset, src_coef_arrays, dst_coef_arrays); break; case JXFORM_ROT_180: do_rot_180(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset, src_coef_arrays, dst_coef_arrays); break; case JXFORM_ROT_270: do_rot_270(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset, src_coef_arrays, dst_coef_arrays); break; case JXFORM_WIPE: do_wipe(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset, src_coef_arrays, info->drop_width, info->drop_height); break; } } /* jtransform_perfect_transform * * Determine whether lossless transformation is perfectly * possible for a specified image and transformation. * * Inputs: * image_width, image_height: source image dimensions. * MCU_width, MCU_height: pixel dimensions of MCU. * transform: transformation identifier. * Parameter sources from initialized jpeg_struct * (after reading source header): * image_width = cinfo.image_width * image_height = cinfo.image_height * MCU_width = cinfo.max_h_samp_factor * cinfo.block_size * MCU_height = cinfo.max_v_samp_factor * cinfo.block_size * Result: * TRUE = perfect transformation possible * FALSE = perfect transformation not possible * (may use custom action then) */ GLOBAL(boolean) jtransform_perfect_transform(JDIMENSION image_width, JDIMENSION image_height, int MCU_width, int MCU_height, JXFORM_CODE transform) { boolean result = TRUE; /* initialize TRUE */ switch (transform) { case JXFORM_FLIP_H: case JXFORM_ROT_270: if (image_width % (JDIMENSION) MCU_width) result = FALSE; break; case JXFORM_FLIP_V: case JXFORM_ROT_90: if (image_height % (JDIMENSION) MCU_height) result = FALSE; break; case JXFORM_TRANSVERSE: case JXFORM_ROT_180: if (image_width % (JDIMENSION) MCU_width) result = FALSE; if (image_height % (JDIMENSION) MCU_height) result = FALSE; break; default: break; } return result; } #endif /* TRANSFORMS_SUPPORTED */ /* Setup decompression object to save desired markers in memory. * This must be called before jpeg_read_header() to have the desired effect. */ GLOBAL(void) jcopy_markers_setup (j_decompress_ptr srcinfo, JCOPY_OPTION option) { #ifdef SAVE_MARKERS_SUPPORTED int m; /* Save comments except under NONE option */ if (option != JCOPYOPT_NONE) { jpeg_save_markers(srcinfo, JPEG_COM, 0xFFFF); } /* Save all types of APPn markers iff ALL option */ if (option == JCOPYOPT_ALL) { for (m = 0; m < 16; m++) jpeg_save_markers(srcinfo, JPEG_APP0 + m, 0xFFFF); } #endif /* SAVE_MARKERS_SUPPORTED */ } /* Copy markers saved in the given source object to the destination object. * This should be called just after jpeg_start_compress() or * jpeg_write_coefficients(). * Note that those routines will have written the SOI, and also the * JFIF APP0 or Adobe APP14 markers if selected. */ GLOBAL(void) jcopy_markers_execute (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, JCOPY_OPTION option) { jpeg_saved_marker_ptr marker; /* In the current implementation, we don't actually need to examine the * option flag here; we just copy everything that got saved. * But to avoid confusion, we do not output JFIF and Adobe APP14 markers * if the encoder library already wrote one. */ for (marker = srcinfo->marker_list; marker != NULL; marker = marker->next) { if (dstinfo->write_JFIF_header && marker->marker == JPEG_APP0 && marker->data_length >= 5 && GETJOCTET(marker->data[0]) == 0x4A && GETJOCTET(marker->data[1]) == 0x46 && GETJOCTET(marker->data[2]) == 0x49 && GETJOCTET(marker->data[3]) == 0x46 && GETJOCTET(marker->data[4]) == 0) continue; /* reject duplicate JFIF */ if (dstinfo->write_Adobe_marker && marker->marker == JPEG_APP0+14 && marker->data_length >= 5 && GETJOCTET(marker->data[0]) == 0x41 && GETJOCTET(marker->data[1]) == 0x64 && GETJOCTET(marker->data[2]) == 0x6F && GETJOCTET(marker->data[3]) == 0x62 && GETJOCTET(marker->data[4]) == 0x65) continue; /* reject duplicate Adobe */ #ifdef NEED_FAR_POINTERS /* We could use jpeg_write_marker if the data weren't FAR... */ { unsigned int i; jpeg_write_m_header(dstinfo, marker->marker, marker->data_length); for (i = 0; i < marker->data_length; i++) jpeg_write_m_byte(dstinfo, marker->data[i]); } #else jpeg_write_marker(dstinfo, marker->marker, marker->data, marker->data_length); #endif } } fbi-2.10/jpeg/90/jpeglib.h0000644000175000017500000014020112506525033013265 0ustar jmmjmm/* * jpeglib.h * * Copyright (C) 1991-1998, Thomas G. Lane. * Modified 2002-2013 by Guido Vollbeding. * This file is part of the Independent JPEG Group's software. * For conditions of distribution and use, see the accompanying README file. * * This file defines the application interface for the JPEG library. * Most applications using the library need only include this file, * and perhaps jerror.h if they want to know the exact error codes. */ #ifndef JPEGLIB_H #define JPEGLIB_H /* * First we include the configuration files that record how this * installation of the JPEG library is set up. jconfig.h can be * generated automatically for many systems. jmorecfg.h contains * manual configuration options that most people need not worry about. */ #ifndef JCONFIG_INCLUDED /* in case jinclude.h already did */ #include "jconfig.h" /* widely used configuration options */ #endif #include "jmorecfg.h" /* seldom changed options */ #ifdef __cplusplus #ifndef DONT_USE_EXTERN_C extern "C" { #endif #endif /* Version IDs for the JPEG library. * Might be useful for tests like "#if JPEG_LIB_VERSION >= 90". */ #define JPEG_LIB_VERSION 90 /* Compatibility version 9.0 */ #define JPEG_LIB_VERSION_MAJOR 9 #define JPEG_LIB_VERSION_MINOR 1 /* Various constants determining the sizes of things. * All of these are specified by the JPEG standard, * so don't change them if you want to be compatible. */ #define DCTSIZE 8 /* The basic DCT block is 8x8 coefficients */ #define DCTSIZE2 64 /* DCTSIZE squared; # of elements in a block */ #define NUM_QUANT_TBLS 4 /* Quantization tables are numbered 0..3 */ #define NUM_HUFF_TBLS 4 /* Huffman tables are numbered 0..3 */ #define NUM_ARITH_TBLS 16 /* Arith-coding tables are numbered 0..15 */ #define MAX_COMPS_IN_SCAN 4 /* JPEG limit on # of components in one scan */ #define MAX_SAMP_FACTOR 4 /* JPEG limit on sampling factors */ /* Unfortunately, some bozo at Adobe saw no reason to be bound by the standard; * the PostScript DCT filter can emit files with many more than 10 blocks/MCU. * If you happen to run across such a file, you can up D_MAX_BLOCKS_IN_MCU * to handle it. We even let you do this from the jconfig.h file. However, * we strongly discourage changing C_MAX_BLOCKS_IN_MCU; just because Adobe * sometimes emits noncompliant files doesn't mean you should too. */ #define C_MAX_BLOCKS_IN_MCU 10 /* compressor's limit on blocks per MCU */ #ifndef D_MAX_BLOCKS_IN_MCU #define D_MAX_BLOCKS_IN_MCU 10 /* decompressor's limit on blocks per MCU */ #endif /* Data structures for images (arrays of samples and of DCT coefficients). * On 80x86 machines, the image arrays are too big for near pointers, * but the pointer arrays can fit in near memory. */ typedef JSAMPLE FAR *JSAMPROW; /* ptr to one image row of pixel samples. */ typedef JSAMPROW *JSAMPARRAY; /* ptr to some rows (a 2-D sample array) */ typedef JSAMPARRAY *JSAMPIMAGE; /* a 3-D sample array: top index is color */ typedef JCOEF JBLOCK[DCTSIZE2]; /* one block of coefficients */ typedef JBLOCK FAR *JBLOCKROW; /* pointer to one row of coefficient blocks */ typedef JBLOCKROW *JBLOCKARRAY; /* a 2-D array of coefficient blocks */ typedef JBLOCKARRAY *JBLOCKIMAGE; /* a 3-D array of coefficient blocks */ typedef JCOEF FAR *JCOEFPTR; /* useful in a couple of places */ /* Types for JPEG compression parameters and working tables. */ /* DCT coefficient quantization tables. */ typedef struct { /* This array gives the coefficient quantizers in natural array order * (not the zigzag order in which they are stored in a JPEG DQT marker). * CAUTION: IJG versions prior to v6a kept this array in zigzag order. */ UINT16 quantval[DCTSIZE2]; /* quantization step for each coefficient */ /* This field is used only during compression. It's initialized FALSE when * the table is created, and set TRUE when it's been output to the file. * You could suppress output of a table by setting this to TRUE. * (See jpeg_suppress_tables for an example.) */ boolean sent_table; /* TRUE when table has been output */ } JQUANT_TBL; /* Huffman coding tables. */ typedef struct { /* These two fields directly represent the contents of a JPEG DHT marker */ UINT8 bits[17]; /* bits[k] = # of symbols with codes of */ /* length k bits; bits[0] is unused */ UINT8 huffval[256]; /* The symbols, in order of incr code length */ /* This field is used only during compression. It's initialized FALSE when * the table is created, and set TRUE when it's been output to the file. * You could suppress output of a table by setting this to TRUE. * (See jpeg_suppress_tables for an example.) */ boolean sent_table; /* TRUE when table has been output */ } JHUFF_TBL; /* Basic info about one component (color channel). */ typedef struct { /* These values are fixed over the whole image. */ /* For compression, they must be supplied by parameter setup; */ /* for decompression, they are read from the SOF marker. */ int component_id; /* identifier for this component (0..255) */ int component_index; /* its index in SOF or cinfo->comp_info[] */ int h_samp_factor; /* horizontal sampling factor (1..4) */ int v_samp_factor; /* vertical sampling factor (1..4) */ int quant_tbl_no; /* quantization table selector (0..3) */ /* These values may vary between scans. */ /* For compression, they must be supplied by parameter setup; */ /* for decompression, they are read from the SOS marker. */ /* The decompressor output side may not use these variables. */ int dc_tbl_no; /* DC entropy table selector (0..3) */ int ac_tbl_no; /* AC entropy table selector (0..3) */ /* Remaining fields should be treated as private by applications. */ /* These values are computed during compression or decompression startup: */ /* Component's size in DCT blocks. * Any dummy blocks added to complete an MCU are not counted; therefore * these values do not depend on whether a scan is interleaved or not. */ JDIMENSION width_in_blocks; JDIMENSION height_in_blocks; /* Size of a DCT block in samples, * reflecting any scaling we choose to apply during the DCT step. * Values from 1 to 16 are supported. * Note that different components may receive different DCT scalings. */ int DCT_h_scaled_size; int DCT_v_scaled_size; /* The downsampled dimensions are the component's actual, unpadded number * of samples at the main buffer (preprocessing/compression interface); * DCT scaling is included, so * downsampled_width = * ceil(image_width * Hi/Hmax * DCT_h_scaled_size/block_size) * and similarly for height. */ JDIMENSION downsampled_width; /* actual width in samples */ JDIMENSION downsampled_height; /* actual height in samples */ /* For decompression, in cases where some of the components will be * ignored (eg grayscale output from YCbCr image), we can skip most * computations for the unused components. * For compression, some of the components will need further quantization * scale by factor of 2 after DCT (eg BG_YCC output from normal RGB input). * The field is first set TRUE for decompression, FALSE for compression * in initial_setup, and then adapted in color conversion setup. */ boolean component_needed; /* These values are computed before starting a scan of the component. */ /* The decompressor output side may not use these variables. */ int MCU_width; /* number of blocks per MCU, horizontally */ int MCU_height; /* number of blocks per MCU, vertically */ int MCU_blocks; /* MCU_width * MCU_height */ int MCU_sample_width; /* MCU width in samples: MCU_width * DCT_h_scaled_size */ int last_col_width; /* # of non-dummy blocks across in last MCU */ int last_row_height; /* # of non-dummy blocks down in last MCU */ /* Saved quantization table for component; NULL if none yet saved. * See jdinput.c comments about the need for this information. * This field is currently used only for decompression. */ JQUANT_TBL * quant_table; /* Private per-component storage for DCT or IDCT subsystem. */ void * dct_table; } jpeg_component_info; /* The script for encoding a multiple-scan file is an array of these: */ typedef struct { int comps_in_scan; /* number of components encoded in this scan */ int component_index[MAX_COMPS_IN_SCAN]; /* their SOF/comp_info[] indexes */ int Ss, Se; /* progressive JPEG spectral selection parms */ int Ah, Al; /* progressive JPEG successive approx. parms */ } jpeg_scan_info; /* The decompressor can save APPn and COM markers in a list of these: */ typedef struct jpeg_marker_struct FAR * jpeg_saved_marker_ptr; struct jpeg_marker_struct { jpeg_saved_marker_ptr next; /* next in list, or NULL */ UINT8 marker; /* marker code: JPEG_COM, or JPEG_APP0+n */ unsigned int original_length; /* # bytes of data in the file */ unsigned int data_length; /* # bytes of data saved at data[] */ JOCTET FAR * data; /* the data contained in the marker */ /* the marker length word is not counted in data_length or original_length */ }; /* Known color spaces. */ typedef enum { JCS_UNKNOWN, /* error/unspecified */ JCS_GRAYSCALE, /* monochrome */ JCS_RGB, /* red/green/blue, standard RGB (sRGB) */ JCS_YCbCr, /* Y/Cb/Cr (also known as YUV), standard YCC */ JCS_CMYK, /* C/M/Y/K */ JCS_YCCK, /* Y/Cb/Cr/K */ JCS_BG_RGB, /* big gamut red/green/blue, bg-sRGB */ JCS_BG_YCC /* big gamut Y/Cb/Cr, bg-sYCC */ } J_COLOR_SPACE; /* Supported color transforms. */ typedef enum { JCT_NONE = 0, JCT_SUBTRACT_GREEN = 1 } J_COLOR_TRANSFORM; /* DCT/IDCT algorithm options. */ typedef enum { JDCT_ISLOW, /* slow but accurate integer algorithm */ JDCT_IFAST, /* faster, less accurate integer method */ JDCT_FLOAT /* floating-point: accurate, fast on fast HW */ } J_DCT_METHOD; #ifndef JDCT_DEFAULT /* may be overridden in jconfig.h */ #define JDCT_DEFAULT JDCT_ISLOW #endif #ifndef JDCT_FASTEST /* may be overridden in jconfig.h */ #define JDCT_FASTEST JDCT_IFAST #endif /* Dithering options for decompression. */ typedef enum { JDITHER_NONE, /* no dithering */ JDITHER_ORDERED, /* simple ordered dither */ JDITHER_FS /* Floyd-Steinberg error diffusion dither */ } J_DITHER_MODE; /* Common fields between JPEG compression and decompression master structs. */ #define jpeg_common_fields \ struct jpeg_error_mgr * err; /* Error handler module */\ struct jpeg_memory_mgr * mem; /* Memory manager module */\ struct jpeg_progress_mgr * progress; /* Progress monitor, or NULL if none */\ void * client_data; /* Available for use by application */\ boolean is_decompressor; /* So common code can tell which is which */\ int global_state /* For checking call sequence validity */ /* Routines that are to be used by both halves of the library are declared * to receive a pointer to this structure. There are no actual instances of * jpeg_common_struct, only of jpeg_compress_struct and jpeg_decompress_struct. */ struct jpeg_common_struct { jpeg_common_fields; /* Fields common to both master struct types */ /* Additional fields follow in an actual jpeg_compress_struct or * jpeg_decompress_struct. All three structs must agree on these * initial fields! (This would be a lot cleaner in C++.) */ }; typedef struct jpeg_common_struct * j_common_ptr; typedef struct jpeg_compress_struct * j_compress_ptr; typedef struct jpeg_decompress_struct * j_decompress_ptr; /* Master record for a compression instance */ struct jpeg_compress_struct { jpeg_common_fields; /* Fields shared with jpeg_decompress_struct */ /* Destination for compressed data */ struct jpeg_destination_mgr * dest; /* Description of source image --- these fields must be filled in by * outer application before starting compression. in_color_space must * be correct before you can even call jpeg_set_defaults(). */ JDIMENSION image_width; /* input image width */ JDIMENSION image_height; /* input image height */ int input_components; /* # of color components in input image */ J_COLOR_SPACE in_color_space; /* colorspace of input image */ double input_gamma; /* image gamma of input image */ /* Compression parameters --- these fields must be set before calling * jpeg_start_compress(). We recommend calling jpeg_set_defaults() to * initialize everything to reasonable defaults, then changing anything * the application specifically wants to change. That way you won't get * burnt when new parameters are added. Also note that there are several * helper routines to simplify changing parameters. */ unsigned int scale_num, scale_denom; /* fraction by which to scale image */ JDIMENSION jpeg_width; /* scaled JPEG image width */ JDIMENSION jpeg_height; /* scaled JPEG image height */ /* Dimensions of actual JPEG image that will be written to file, * derived from input dimensions by scaling factors above. * These fields are computed by jpeg_start_compress(). * You can also use jpeg_calc_jpeg_dimensions() to determine these values * in advance of calling jpeg_start_compress(). */ int data_precision; /* bits of precision in image data */ int num_components; /* # of color components in JPEG image */ J_COLOR_SPACE jpeg_color_space; /* colorspace of JPEG image */ jpeg_component_info * comp_info; /* comp_info[i] describes component that appears i'th in SOF */ JQUANT_TBL * quant_tbl_ptrs[NUM_QUANT_TBLS]; int q_scale_factor[NUM_QUANT_TBLS]; /* ptrs to coefficient quantization tables, or NULL if not defined, * and corresponding scale factors (percentage, initialized 100). */ JHUFF_TBL * dc_huff_tbl_ptrs[NUM_HUFF_TBLS]; JHUFF_TBL * ac_huff_tbl_ptrs[NUM_HUFF_TBLS]; /* ptrs to Huffman coding tables, or NULL if not defined */ UINT8 arith_dc_L[NUM_ARITH_TBLS]; /* L values for DC arith-coding tables */ UINT8 arith_dc_U[NUM_ARITH_TBLS]; /* U values for DC arith-coding tables */ UINT8 arith_ac_K[NUM_ARITH_TBLS]; /* Kx values for AC arith-coding tables */ int num_scans; /* # of entries in scan_info array */ const jpeg_scan_info * scan_info; /* script for multi-scan file, or NULL */ /* The default value of scan_info is NULL, which causes a single-scan * sequential JPEG file to be emitted. To create a multi-scan file, * set num_scans and scan_info to point to an array of scan definitions. */ boolean raw_data_in; /* TRUE=caller supplies downsampled data */ boolean arith_code; /* TRUE=arithmetic coding, FALSE=Huffman */ boolean optimize_coding; /* TRUE=optimize entropy encoding parms */ boolean CCIR601_sampling; /* TRUE=first samples are cosited */ boolean do_fancy_downsampling; /* TRUE=apply fancy downsampling */ int smoothing_factor; /* 1..100, or 0 for no input smoothing */ J_DCT_METHOD dct_method; /* DCT algorithm selector */ /* The restart interval can be specified in absolute MCUs by setting * restart_interval, or in MCU rows by setting restart_in_rows * (in which case the correct restart_interval will be figured * for each scan). */ unsigned int restart_interval; /* MCUs per restart, or 0 for no restart */ int restart_in_rows; /* if > 0, MCU rows per restart interval */ /* Parameters controlling emission of special markers. */ boolean write_JFIF_header; /* should a JFIF marker be written? */ UINT8 JFIF_major_version; /* What to write for the JFIF version number */ UINT8 JFIF_minor_version; /* These three values are not used by the JPEG code, merely copied */ /* into the JFIF APP0 marker. density_unit can be 0 for unknown, */ /* 1 for dots/inch, or 2 for dots/cm. Note that the pixel aspect */ /* ratio is defined by X_density/Y_density even when density_unit=0. */ UINT8 density_unit; /* JFIF code for pixel size units */ UINT16 X_density; /* Horizontal pixel density */ UINT16 Y_density; /* Vertical pixel density */ boolean write_Adobe_marker; /* should an Adobe marker be written? */ J_COLOR_TRANSFORM color_transform; /* Color transform identifier, writes LSE marker if nonzero */ /* State variable: index of next scanline to be written to * jpeg_write_scanlines(). Application may use this to control its * processing loop, e.g., "while (next_scanline < image_height)". */ JDIMENSION next_scanline; /* 0 .. image_height-1 */ /* Remaining fields are known throughout compressor, but generally * should not be touched by a surrounding application. */ /* * These fields are computed during compression startup */ boolean progressive_mode; /* TRUE if scan script uses progressive mode */ int max_h_samp_factor; /* largest h_samp_factor */ int max_v_samp_factor; /* largest v_samp_factor */ int min_DCT_h_scaled_size; /* smallest DCT_h_scaled_size of any component */ int min_DCT_v_scaled_size; /* smallest DCT_v_scaled_size of any component */ JDIMENSION total_iMCU_rows; /* # of iMCU rows to be input to coef ctlr */ /* The coefficient controller receives data in units of MCU rows as defined * for fully interleaved scans (whether the JPEG file is interleaved or not). * There are v_samp_factor * DCTSIZE sample rows of each component in an * "iMCU" (interleaved MCU) row. */ /* * These fields are valid during any one scan. * They describe the components and MCUs actually appearing in the scan. */ int comps_in_scan; /* # of JPEG components in this scan */ jpeg_component_info * cur_comp_info[MAX_COMPS_IN_SCAN]; /* *cur_comp_info[i] describes component that appears i'th in SOS */ JDIMENSION MCUs_per_row; /* # of MCUs across the image */ JDIMENSION MCU_rows_in_scan; /* # of MCU rows in the image */ int blocks_in_MCU; /* # of DCT blocks per MCU */ int MCU_membership[C_MAX_BLOCKS_IN_MCU]; /* MCU_membership[i] is index in cur_comp_info of component owning */ /* i'th block in an MCU */ int Ss, Se, Ah, Al; /* progressive JPEG parameters for scan */ int block_size; /* the basic DCT block size: 1..16 */ const int * natural_order; /* natural-order position array */ int lim_Se; /* min( Se, DCTSIZE2-1 ) */ /* * Links to compression subobjects (methods and private variables of modules) */ struct jpeg_comp_master * master; struct jpeg_c_main_controller * main; struct jpeg_c_prep_controller * prep; struct jpeg_c_coef_controller * coef; struct jpeg_marker_writer * marker; struct jpeg_color_converter * cconvert; struct jpeg_downsampler * downsample; struct jpeg_forward_dct * fdct; struct jpeg_entropy_encoder * entropy; jpeg_scan_info * script_space; /* workspace for jpeg_simple_progression */ int script_space_size; }; /* Master record for a decompression instance */ struct jpeg_decompress_struct { jpeg_common_fields; /* Fields shared with jpeg_compress_struct */ /* Source of compressed data */ struct jpeg_source_mgr * src; /* Basic description of image --- filled in by jpeg_read_header(). */ /* Application may inspect these values to decide how to process image. */ JDIMENSION image_width; /* nominal image width (from SOF marker) */ JDIMENSION image_height; /* nominal image height */ int num_components; /* # of color components in JPEG image */ J_COLOR_SPACE jpeg_color_space; /* colorspace of JPEG image */ /* Decompression processing parameters --- these fields must be set before * calling jpeg_start_decompress(). Note that jpeg_read_header() initializes * them to default values. */ J_COLOR_SPACE out_color_space; /* colorspace for output */ unsigned int scale_num, scale_denom; /* fraction by which to scale image */ double output_gamma; /* image gamma wanted in output */ boolean buffered_image; /* TRUE=multiple output passes */ boolean raw_data_out; /* TRUE=downsampled data wanted */ J_DCT_METHOD dct_method; /* IDCT algorithm selector */ boolean do_fancy_upsampling; /* TRUE=apply fancy upsampling */ boolean do_block_smoothing; /* TRUE=apply interblock smoothing */ boolean quantize_colors; /* TRUE=colormapped output wanted */ /* the following are ignored if not quantize_colors: */ J_DITHER_MODE dither_mode; /* type of color dithering to use */ boolean two_pass_quantize; /* TRUE=use two-pass color quantization */ int desired_number_of_colors; /* max # colors to use in created colormap */ /* these are significant only in buffered-image mode: */ boolean enable_1pass_quant; /* enable future use of 1-pass quantizer */ boolean enable_external_quant;/* enable future use of external colormap */ boolean enable_2pass_quant; /* enable future use of 2-pass quantizer */ /* Description of actual output image that will be returned to application. * These fields are computed by jpeg_start_decompress(). * You can also use jpeg_calc_output_dimensions() to determine these values * in advance of calling jpeg_start_decompress(). */ JDIMENSION output_width; /* scaled image width */ JDIMENSION output_height; /* scaled image height */ int out_color_components; /* # of color components in out_color_space */ int output_components; /* # of color components returned */ /* output_components is 1 (a colormap index) when quantizing colors; * otherwise it equals out_color_components. */ int rec_outbuf_height; /* min recommended height of scanline buffer */ /* If the buffer passed to jpeg_read_scanlines() is less than this many rows * high, space and time will be wasted due to unnecessary data copying. * Usually rec_outbuf_height will be 1 or 2, at most 4. */ /* When quantizing colors, the output colormap is described by these fields. * The application can supply a colormap by setting colormap non-NULL before * calling jpeg_start_decompress; otherwise a colormap is created during * jpeg_start_decompress or jpeg_start_output. * The map has out_color_components rows and actual_number_of_colors columns. */ int actual_number_of_colors; /* number of entries in use */ JSAMPARRAY colormap; /* The color map as a 2-D pixel array */ /* State variables: these variables indicate the progress of decompression. * The application may examine these but must not modify them. */ /* Row index of next scanline to be read from jpeg_read_scanlines(). * Application may use this to control its processing loop, e.g., * "while (output_scanline < output_height)". */ JDIMENSION output_scanline; /* 0 .. output_height-1 */ /* Current input scan number and number of iMCU rows completed in scan. * These indicate the progress of the decompressor input side. */ int input_scan_number; /* Number of SOS markers seen so far */ JDIMENSION input_iMCU_row; /* Number of iMCU rows completed */ /* The "output scan number" is the notional scan being displayed by the * output side. The decompressor will not allow output scan/row number * to get ahead of input scan/row, but it can fall arbitrarily far behind. */ int output_scan_number; /* Nominal scan number being displayed */ JDIMENSION output_iMCU_row; /* Number of iMCU rows read */ /* Current progression status. coef_bits[c][i] indicates the precision * with which component c's DCT coefficient i (in zigzag order) is known. * It is -1 when no data has yet been received, otherwise it is the point * transform (shift) value for the most recent scan of the coefficient * (thus, 0 at completion of the progression). * This pointer is NULL when reading a non-progressive file. */ int (*coef_bits)[DCTSIZE2]; /* -1 or current Al value for each coef */ /* Internal JPEG parameters --- the application usually need not look at * these fields. Note that the decompressor output side may not use * any parameters that can change between scans. */ /* Quantization and Huffman tables are carried forward across input * datastreams when processing abbreviated JPEG datastreams. */ JQUANT_TBL * quant_tbl_ptrs[NUM_QUANT_TBLS]; /* ptrs to coefficient quantization tables, or NULL if not defined */ JHUFF_TBL * dc_huff_tbl_ptrs[NUM_HUFF_TBLS]; JHUFF_TBL * ac_huff_tbl_ptrs[NUM_HUFF_TBLS]; /* ptrs to Huffman coding tables, or NULL if not defined */ /* These parameters are never carried across datastreams, since they * are given in SOF/SOS markers or defined to be reset by SOI. */ int data_precision; /* bits of precision in image data */ jpeg_component_info * comp_info; /* comp_info[i] describes component that appears i'th in SOF */ boolean is_baseline; /* TRUE if Baseline SOF0 encountered */ boolean progressive_mode; /* TRUE if SOFn specifies progressive mode */ boolean arith_code; /* TRUE=arithmetic coding, FALSE=Huffman */ UINT8 arith_dc_L[NUM_ARITH_TBLS]; /* L values for DC arith-coding tables */ UINT8 arith_dc_U[NUM_ARITH_TBLS]; /* U values for DC arith-coding tables */ UINT8 arith_ac_K[NUM_ARITH_TBLS]; /* Kx values for AC arith-coding tables */ unsigned int restart_interval; /* MCUs per restart interval, or 0 for no restart */ /* These fields record data obtained from optional markers recognized by * the JPEG library. */ boolean saw_JFIF_marker; /* TRUE iff a JFIF APP0 marker was found */ /* Data copied from JFIF marker; only valid if saw_JFIF_marker is TRUE: */ UINT8 JFIF_major_version; /* JFIF version number */ UINT8 JFIF_minor_version; UINT8 density_unit; /* JFIF code for pixel size units */ UINT16 X_density; /* Horizontal pixel density */ UINT16 Y_density; /* Vertical pixel density */ boolean saw_Adobe_marker; /* TRUE iff an Adobe APP14 marker was found */ UINT8 Adobe_transform; /* Color transform code from Adobe marker */ J_COLOR_TRANSFORM color_transform; /* Color transform identifier derived from LSE marker, otherwise zero */ boolean CCIR601_sampling; /* TRUE=first samples are cosited */ /* Aside from the specific data retained from APPn markers known to the * library, the uninterpreted contents of any or all APPn and COM markers * can be saved in a list for examination by the application. */ jpeg_saved_marker_ptr marker_list; /* Head of list of saved markers */ /* Remaining fields are known throughout decompressor, but generally * should not be touched by a surrounding application. */ /* * These fields are computed during decompression startup */ int max_h_samp_factor; /* largest h_samp_factor */ int max_v_samp_factor; /* largest v_samp_factor */ int min_DCT_h_scaled_size; /* smallest DCT_h_scaled_size of any component */ int min_DCT_v_scaled_size; /* smallest DCT_v_scaled_size of any component */ JDIMENSION total_iMCU_rows; /* # of iMCU rows in image */ /* The coefficient controller's input and output progress is measured in * units of "iMCU" (interleaved MCU) rows. These are the same as MCU rows * in fully interleaved JPEG scans, but are used whether the scan is * interleaved or not. We define an iMCU row as v_samp_factor DCT block * rows of each component. Therefore, the IDCT output contains * v_samp_factor*DCT_v_scaled_size sample rows of a component per iMCU row. */ JSAMPLE * sample_range_limit; /* table for fast range-limiting */ /* * These fields are valid during any one scan. * They describe the components and MCUs actually appearing in the scan. * Note that the decompressor output side must not use these fields. */ int comps_in_scan; /* # of JPEG components in this scan */ jpeg_component_info * cur_comp_info[MAX_COMPS_IN_SCAN]; /* *cur_comp_info[i] describes component that appears i'th in SOS */ JDIMENSION MCUs_per_row; /* # of MCUs across the image */ JDIMENSION MCU_rows_in_scan; /* # of MCU rows in the image */ int blocks_in_MCU; /* # of DCT blocks per MCU */ int MCU_membership[D_MAX_BLOCKS_IN_MCU]; /* MCU_membership[i] is index in cur_comp_info of component owning */ /* i'th block in an MCU */ int Ss, Se, Ah, Al; /* progressive JPEG parameters for scan */ /* These fields are derived from Se of first SOS marker. */ int block_size; /* the basic DCT block size: 1..16 */ const int * natural_order; /* natural-order position array for entropy decode */ int lim_Se; /* min( Se, DCTSIZE2-1 ) for entropy decode */ /* This field is shared between entropy decoder and marker parser. * It is either zero or the code of a JPEG marker that has been * read from the data source, but has not yet been processed. */ int unread_marker; /* * Links to decompression subobjects (methods, private variables of modules) */ struct jpeg_decomp_master * master; struct jpeg_d_main_controller * main; struct jpeg_d_coef_controller * coef; struct jpeg_d_post_controller * post; struct jpeg_input_controller * inputctl; struct jpeg_marker_reader * marker; struct jpeg_entropy_decoder * entropy; struct jpeg_inverse_dct * idct; struct jpeg_upsampler * upsample; struct jpeg_color_deconverter * cconvert; struct jpeg_color_quantizer * cquantize; }; /* "Object" declarations for JPEG modules that may be supplied or called * directly by the surrounding application. * As with all objects in the JPEG library, these structs only define the * publicly visible methods and state variables of a module. Additional * private fields may exist after the public ones. */ /* Error handler object */ struct jpeg_error_mgr { /* Error exit handler: does not return to caller */ JMETHOD(noreturn_t, error_exit, (j_common_ptr cinfo)); /* Conditionally emit a trace or warning message */ JMETHOD(void, emit_message, (j_common_ptr cinfo, int msg_level)); /* Routine that actually outputs a trace or error message */ JMETHOD(void, output_message, (j_common_ptr cinfo)); /* Format a message string for the most recent JPEG error or message */ JMETHOD(void, format_message, (j_common_ptr cinfo, char * buffer)); #define JMSG_LENGTH_MAX 200 /* recommended size of format_message buffer */ /* Reset error state variables at start of a new image */ JMETHOD(void, reset_error_mgr, (j_common_ptr cinfo)); /* The message ID code and any parameters are saved here. * A message can have one string parameter or up to 8 int parameters. */ int msg_code; #define JMSG_STR_PARM_MAX 80 union { int i[8]; char s[JMSG_STR_PARM_MAX]; } msg_parm; /* Standard state variables for error facility */ int trace_level; /* max msg_level that will be displayed */ /* For recoverable corrupt-data errors, we emit a warning message, * but keep going unless emit_message chooses to abort. emit_message * should count warnings in num_warnings. The surrounding application * can check for bad data by seeing if num_warnings is nonzero at the * end of processing. */ long num_warnings; /* number of corrupt-data warnings */ /* These fields point to the table(s) of error message strings. * An application can change the table pointer to switch to a different * message list (typically, to change the language in which errors are * reported). Some applications may wish to add additional error codes * that will be handled by the JPEG library error mechanism; the second * table pointer is used for this purpose. * * First table includes all errors generated by JPEG library itself. * Error code 0 is reserved for a "no such error string" message. */ const char * const * jpeg_message_table; /* Library errors */ int last_jpeg_message; /* Table contains strings 0..last_jpeg_message */ /* Second table can be added by application (see cjpeg/djpeg for example). * It contains strings numbered first_addon_message..last_addon_message. */ const char * const * addon_message_table; /* Non-library errors */ int first_addon_message; /* code for first string in addon table */ int last_addon_message; /* code for last string in addon table */ }; /* Progress monitor object */ struct jpeg_progress_mgr { JMETHOD(void, progress_monitor, (j_common_ptr cinfo)); long pass_counter; /* work units completed in this pass */ long pass_limit; /* total number of work units in this pass */ int completed_passes; /* passes completed so far */ int total_passes; /* total number of passes expected */ }; /* Data destination object for compression */ struct jpeg_destination_mgr { JOCTET * next_output_byte; /* => next byte to write in buffer */ size_t free_in_buffer; /* # of byte spaces remaining in buffer */ JMETHOD(void, init_destination, (j_compress_ptr cinfo)); JMETHOD(boolean, empty_output_buffer, (j_compress_ptr cinfo)); JMETHOD(void, term_destination, (j_compress_ptr cinfo)); }; /* Data source object for decompression */ struct jpeg_source_mgr { const JOCTET * next_input_byte; /* => next byte to read from buffer */ size_t bytes_in_buffer; /* # of bytes remaining in buffer */ JMETHOD(void, init_source, (j_decompress_ptr cinfo)); JMETHOD(boolean, fill_input_buffer, (j_decompress_ptr cinfo)); JMETHOD(void, skip_input_data, (j_decompress_ptr cinfo, long num_bytes)); JMETHOD(boolean, resync_to_restart, (j_decompress_ptr cinfo, int desired)); JMETHOD(void, term_source, (j_decompress_ptr cinfo)); }; /* Memory manager object. * Allocates "small" objects (a few K total), "large" objects (tens of K), * and "really big" objects (virtual arrays with backing store if needed). * The memory manager does not allow individual objects to be freed; rather, * each created object is assigned to a pool, and whole pools can be freed * at once. This is faster and more convenient than remembering exactly what * to free, especially where malloc()/free() are not too speedy. * NB: alloc routines never return NULL. They exit to error_exit if not * successful. */ #define JPOOL_PERMANENT 0 /* lasts until master record is destroyed */ #define JPOOL_IMAGE 1 /* lasts until done with image/datastream */ #define JPOOL_NUMPOOLS 2 typedef struct jvirt_sarray_control * jvirt_sarray_ptr; typedef struct jvirt_barray_control * jvirt_barray_ptr; struct jpeg_memory_mgr { /* Method pointers */ JMETHOD(void *, alloc_small, (j_common_ptr cinfo, int pool_id, size_t sizeofobject)); JMETHOD(void FAR *, alloc_large, (j_common_ptr cinfo, int pool_id, size_t sizeofobject)); JMETHOD(JSAMPARRAY, alloc_sarray, (j_common_ptr cinfo, int pool_id, JDIMENSION samplesperrow, JDIMENSION numrows)); JMETHOD(JBLOCKARRAY, alloc_barray, (j_common_ptr cinfo, int pool_id, JDIMENSION blocksperrow, JDIMENSION numrows)); JMETHOD(jvirt_sarray_ptr, request_virt_sarray, (j_common_ptr cinfo, int pool_id, boolean pre_zero, JDIMENSION samplesperrow, JDIMENSION numrows, JDIMENSION maxaccess)); JMETHOD(jvirt_barray_ptr, request_virt_barray, (j_common_ptr cinfo, int pool_id, boolean pre_zero, JDIMENSION blocksperrow, JDIMENSION numrows, JDIMENSION maxaccess)); JMETHOD(void, realize_virt_arrays, (j_common_ptr cinfo)); JMETHOD(JSAMPARRAY, access_virt_sarray, (j_common_ptr cinfo, jvirt_sarray_ptr ptr, JDIMENSION start_row, JDIMENSION num_rows, boolean writable)); JMETHOD(JBLOCKARRAY, access_virt_barray, (j_common_ptr cinfo, jvirt_barray_ptr ptr, JDIMENSION start_row, JDIMENSION num_rows, boolean writable)); JMETHOD(void, free_pool, (j_common_ptr cinfo, int pool_id)); JMETHOD(void, self_destruct, (j_common_ptr cinfo)); /* Limit on memory allocation for this JPEG object. (Note that this is * merely advisory, not a guaranteed maximum; it only affects the space * used for virtual-array buffers.) May be changed by outer application * after creating the JPEG object. */ long max_memory_to_use; /* Maximum allocation request accepted by alloc_large. */ long max_alloc_chunk; }; /* Routine signature for application-supplied marker processing methods. * Need not pass marker code since it is stored in cinfo->unread_marker. */ typedef JMETHOD(boolean, jpeg_marker_parser_method, (j_decompress_ptr cinfo)); /* Declarations for routines called by application. * The JPP macro hides prototype parameters from compilers that can't cope. * Note JPP requires double parentheses. */ #ifdef HAVE_PROTOTYPES #define JPP(arglist) arglist #else #define JPP(arglist) () #endif /* Short forms of external names for systems with brain-damaged linkers. * We shorten external names to be unique in the first six letters, which * is good enough for all known systems. * (If your compiler itself needs names to be unique in less than 15 * characters, you are out of luck. Get a better compiler.) */ #ifdef NEED_SHORT_EXTERNAL_NAMES #define jpeg_std_error jStdError #define jpeg_CreateCompress jCreaCompress #define jpeg_CreateDecompress jCreaDecompress #define jpeg_destroy_compress jDestCompress #define jpeg_destroy_decompress jDestDecompress #define jpeg_stdio_dest jStdDest #define jpeg_stdio_src jStdSrc #define jpeg_mem_dest jMemDest #define jpeg_mem_src jMemSrc #define jpeg_set_defaults jSetDefaults #define jpeg_set_colorspace jSetColorspace #define jpeg_default_colorspace jDefColorspace #define jpeg_set_quality jSetQuality #define jpeg_set_linear_quality jSetLQuality #define jpeg_default_qtables jDefQTables #define jpeg_add_quant_table jAddQuantTable #define jpeg_quality_scaling jQualityScaling #define jpeg_simple_progression jSimProgress #define jpeg_suppress_tables jSuppressTables #define jpeg_alloc_quant_table jAlcQTable #define jpeg_alloc_huff_table jAlcHTable #define jpeg_start_compress jStrtCompress #define jpeg_write_scanlines jWrtScanlines #define jpeg_finish_compress jFinCompress #define jpeg_calc_jpeg_dimensions jCjpegDimensions #define jpeg_write_raw_data jWrtRawData #define jpeg_write_marker jWrtMarker #define jpeg_write_m_header jWrtMHeader #define jpeg_write_m_byte jWrtMByte #define jpeg_write_tables jWrtTables #define jpeg_read_header jReadHeader #define jpeg_start_decompress jStrtDecompress #define jpeg_read_scanlines jReadScanlines #define jpeg_finish_decompress jFinDecompress #define jpeg_read_raw_data jReadRawData #define jpeg_has_multiple_scans jHasMultScn #define jpeg_start_output jStrtOutput #define jpeg_finish_output jFinOutput #define jpeg_input_complete jInComplete #define jpeg_new_colormap jNewCMap #define jpeg_consume_input jConsumeInput #define jpeg_core_output_dimensions jCoreDimensions #define jpeg_calc_output_dimensions jCalcDimensions #define jpeg_save_markers jSaveMarkers #define jpeg_set_marker_processor jSetMarker #define jpeg_read_coefficients jReadCoefs #define jpeg_write_coefficients jWrtCoefs #define jpeg_copy_critical_parameters jCopyCrit #define jpeg_abort_compress jAbrtCompress #define jpeg_abort_decompress jAbrtDecompress #define jpeg_abort jAbort #define jpeg_destroy jDestroy #define jpeg_resync_to_restart jResyncRestart #endif /* NEED_SHORT_EXTERNAL_NAMES */ /* Default error-management setup */ EXTERN(struct jpeg_error_mgr *) jpeg_std_error JPP((struct jpeg_error_mgr * err)); /* Initialization of JPEG compression objects. * jpeg_create_compress() and jpeg_create_decompress() are the exported * names that applications should call. These expand to calls on * jpeg_CreateCompress and jpeg_CreateDecompress with additional information * passed for version mismatch checking. * NB: you must set up the error-manager BEFORE calling jpeg_create_xxx. */ #define jpeg_create_compress(cinfo) \ jpeg_CreateCompress((cinfo), JPEG_LIB_VERSION, \ (size_t) sizeof(struct jpeg_compress_struct)) #define jpeg_create_decompress(cinfo) \ jpeg_CreateDecompress((cinfo), JPEG_LIB_VERSION, \ (size_t) sizeof(struct jpeg_decompress_struct)) EXTERN(void) jpeg_CreateCompress JPP((j_compress_ptr cinfo, int version, size_t structsize)); EXTERN(void) jpeg_CreateDecompress JPP((j_decompress_ptr cinfo, int version, size_t structsize)); /* Destruction of JPEG compression objects */ EXTERN(void) jpeg_destroy_compress JPP((j_compress_ptr cinfo)); EXTERN(void) jpeg_destroy_decompress JPP((j_decompress_ptr cinfo)); /* Standard data source and destination managers: stdio streams. */ /* Caller is responsible for opening the file before and closing after. */ EXTERN(void) jpeg_stdio_dest JPP((j_compress_ptr cinfo, FILE * outfile)); EXTERN(void) jpeg_stdio_src JPP((j_decompress_ptr cinfo, FILE * infile)); /* Data source and destination managers: memory buffers. */ EXTERN(void) jpeg_mem_dest JPP((j_compress_ptr cinfo, unsigned char ** outbuffer, unsigned long * outsize)); EXTERN(void) jpeg_mem_src JPP((j_decompress_ptr cinfo, unsigned char * inbuffer, unsigned long insize)); /* Default parameter setup for compression */ EXTERN(void) jpeg_set_defaults JPP((j_compress_ptr cinfo)); /* Compression parameter setup aids */ EXTERN(void) jpeg_set_colorspace JPP((j_compress_ptr cinfo, J_COLOR_SPACE colorspace)); EXTERN(void) jpeg_default_colorspace JPP((j_compress_ptr cinfo)); EXTERN(void) jpeg_set_quality JPP((j_compress_ptr cinfo, int quality, boolean force_baseline)); EXTERN(void) jpeg_set_linear_quality JPP((j_compress_ptr cinfo, int scale_factor, boolean force_baseline)); EXTERN(void) jpeg_default_qtables JPP((j_compress_ptr cinfo, boolean force_baseline)); EXTERN(void) jpeg_add_quant_table JPP((j_compress_ptr cinfo, int which_tbl, const unsigned int *basic_table, int scale_factor, boolean force_baseline)); EXTERN(int) jpeg_quality_scaling JPP((int quality)); EXTERN(void) jpeg_simple_progression JPP((j_compress_ptr cinfo)); EXTERN(void) jpeg_suppress_tables JPP((j_compress_ptr cinfo, boolean suppress)); EXTERN(JQUANT_TBL *) jpeg_alloc_quant_table JPP((j_common_ptr cinfo)); EXTERN(JHUFF_TBL *) jpeg_alloc_huff_table JPP((j_common_ptr cinfo)); /* Main entry points for compression */ EXTERN(void) jpeg_start_compress JPP((j_compress_ptr cinfo, boolean write_all_tables)); EXTERN(JDIMENSION) jpeg_write_scanlines JPP((j_compress_ptr cinfo, JSAMPARRAY scanlines, JDIMENSION num_lines)); EXTERN(void) jpeg_finish_compress JPP((j_compress_ptr cinfo)); /* Precalculate JPEG dimensions for current compression parameters. */ EXTERN(void) jpeg_calc_jpeg_dimensions JPP((j_compress_ptr cinfo)); /* Replaces jpeg_write_scanlines when writing raw downsampled data. */ EXTERN(JDIMENSION) jpeg_write_raw_data JPP((j_compress_ptr cinfo, JSAMPIMAGE data, JDIMENSION num_lines)); /* Write a special marker. See libjpeg.txt concerning safe usage. */ EXTERN(void) jpeg_write_marker JPP((j_compress_ptr cinfo, int marker, const JOCTET * dataptr, unsigned int datalen)); /* Same, but piecemeal. */ EXTERN(void) jpeg_write_m_header JPP((j_compress_ptr cinfo, int marker, unsigned int datalen)); EXTERN(void) jpeg_write_m_byte JPP((j_compress_ptr cinfo, int val)); /* Alternate compression function: just write an abbreviated table file */ EXTERN(void) jpeg_write_tables JPP((j_compress_ptr cinfo)); /* Decompression startup: read start of JPEG datastream to see what's there */ EXTERN(int) jpeg_read_header JPP((j_decompress_ptr cinfo, boolean require_image)); /* Return value is one of: */ #define JPEG_SUSPENDED 0 /* Suspended due to lack of input data */ #define JPEG_HEADER_OK 1 /* Found valid image datastream */ #define JPEG_HEADER_TABLES_ONLY 2 /* Found valid table-specs-only datastream */ /* If you pass require_image = TRUE (normal case), you need not check for * a TABLES_ONLY return code; an abbreviated file will cause an error exit. * JPEG_SUSPENDED is only possible if you use a data source module that can * give a suspension return (the stdio source module doesn't). */ /* Main entry points for decompression */ EXTERN(boolean) jpeg_start_decompress JPP((j_decompress_ptr cinfo)); EXTERN(JDIMENSION) jpeg_read_scanlines JPP((j_decompress_ptr cinfo, JSAMPARRAY scanlines, JDIMENSION max_lines)); EXTERN(boolean) jpeg_finish_decompress JPP((j_decompress_ptr cinfo)); /* Replaces jpeg_read_scanlines when reading raw downsampled data. */ EXTERN(JDIMENSION) jpeg_read_raw_data JPP((j_decompress_ptr cinfo, JSAMPIMAGE data, JDIMENSION max_lines)); /* Additional entry points for buffered-image mode. */ EXTERN(boolean) jpeg_has_multiple_scans JPP((j_decompress_ptr cinfo)); EXTERN(boolean) jpeg_start_output JPP((j_decompress_ptr cinfo, int scan_number)); EXTERN(boolean) jpeg_finish_output JPP((j_decompress_ptr cinfo)); EXTERN(boolean) jpeg_input_complete JPP((j_decompress_ptr cinfo)); EXTERN(void) jpeg_new_colormap JPP((j_decompress_ptr cinfo)); EXTERN(int) jpeg_consume_input JPP((j_decompress_ptr cinfo)); /* Return value is one of: */ /* #define JPEG_SUSPENDED 0 Suspended due to lack of input data */ #define JPEG_REACHED_SOS 1 /* Reached start of new scan */ #define JPEG_REACHED_EOI 2 /* Reached end of image */ #define JPEG_ROW_COMPLETED 3 /* Completed one iMCU row */ #define JPEG_SCAN_COMPLETED 4 /* Completed last iMCU row of a scan */ /* Precalculate output dimensions for current decompression parameters. */ EXTERN(void) jpeg_core_output_dimensions JPP((j_decompress_ptr cinfo)); EXTERN(void) jpeg_calc_output_dimensions JPP((j_decompress_ptr cinfo)); /* Control saving of COM and APPn markers into marker_list. */ EXTERN(void) jpeg_save_markers JPP((j_decompress_ptr cinfo, int marker_code, unsigned int length_limit)); /* Install a special processing method for COM or APPn markers. */ EXTERN(void) jpeg_set_marker_processor JPP((j_decompress_ptr cinfo, int marker_code, jpeg_marker_parser_method routine)); /* Read or write raw DCT coefficients --- useful for lossless transcoding. */ EXTERN(jvirt_barray_ptr *) jpeg_read_coefficients JPP((j_decompress_ptr cinfo)); EXTERN(void) jpeg_write_coefficients JPP((j_compress_ptr cinfo, jvirt_barray_ptr * coef_arrays)); EXTERN(void) jpeg_copy_critical_parameters JPP((j_decompress_ptr srcinfo, j_compress_ptr dstinfo)); /* If you choose to abort compression or decompression before completing * jpeg_finish_(de)compress, then you need to clean up to release memory, * temporary files, etc. You can just call jpeg_destroy_(de)compress * if you're done with the JPEG object, but if you want to clean it up and * reuse it, call this: */ EXTERN(void) jpeg_abort_compress JPP((j_compress_ptr cinfo)); EXTERN(void) jpeg_abort_decompress JPP((j_decompress_ptr cinfo)); /* Generic versions of jpeg_abort and jpeg_destroy that work on either * flavor of JPEG object. These may be more convenient in some places. */ EXTERN(void) jpeg_abort JPP((j_common_ptr cinfo)); EXTERN(void) jpeg_destroy JPP((j_common_ptr cinfo)); /* Default restart-marker-resync procedure for use by data source modules */ EXTERN(boolean) jpeg_resync_to_restart JPP((j_decompress_ptr cinfo, int desired)); /* These marker codes are exported since applications and data source modules * are likely to want to use them. */ #define JPEG_RST0 0xD0 /* RST0 marker code */ #define JPEG_EOI 0xD9 /* EOI marker code */ #define JPEG_APP0 0xE0 /* APP0 marker code */ #define JPEG_COM 0xFE /* COM marker code */ /* If we have a brain-damaged compiler that emits warnings (or worse, errors) * for structure definitions that are never filled in, keep it quiet by * supplying dummy definitions for the various substructures. */ #ifdef INCOMPLETE_TYPES_BROKEN #ifndef JPEG_INTERNALS /* will be defined in jpegint.h */ struct jvirt_sarray_control { long dummy; }; struct jvirt_barray_control { long dummy; }; struct jpeg_comp_master { long dummy; }; struct jpeg_c_main_controller { long dummy; }; struct jpeg_c_prep_controller { long dummy; }; struct jpeg_c_coef_controller { long dummy; }; struct jpeg_marker_writer { long dummy; }; struct jpeg_color_converter { long dummy; }; struct jpeg_downsampler { long dummy; }; struct jpeg_forward_dct { long dummy; }; struct jpeg_entropy_encoder { long dummy; }; struct jpeg_decomp_master { long dummy; }; struct jpeg_d_main_controller { long dummy; }; struct jpeg_d_coef_controller { long dummy; }; struct jpeg_d_post_controller { long dummy; }; struct jpeg_input_controller { long dummy; }; struct jpeg_marker_reader { long dummy; }; struct jpeg_entropy_decoder { long dummy; }; struct jpeg_inverse_dct { long dummy; }; struct jpeg_upsampler { long dummy; }; struct jpeg_color_deconverter { long dummy; }; struct jpeg_color_quantizer { long dummy; }; #endif /* JPEG_INTERNALS */ #endif /* INCOMPLETE_TYPES_BROKEN */ /* * The JPEG library modules define JPEG_INTERNALS before including this file. * The internal structure declarations are read only when that is true. * Applications using the library should not include jpegint.h, but may wish * to include jerror.h. */ #ifdef JPEG_INTERNALS #include "jpegint.h" /* fetch private declarations */ #include "jerror.h" /* fetch error codes too */ #endif #ifdef __cplusplus #ifndef DONT_USE_EXTERN_C } #endif #endif #endif /* JPEGLIB_H */ fbi-2.10/jpeg/90/jinclude.h0000644000175000017500000000626212506525033013456 0ustar jmmjmm/* * jinclude.h * * Copyright (C) 1991-1994, Thomas G. Lane. * This file is part of the Independent JPEG Group's software. * For conditions of distribution and use, see the accompanying README file. * * This file exists to provide a single place to fix any problems with * including the wrong system include files. (Common problems are taken * care of by the standard jconfig symbols, but on really weird systems * you may have to edit this file.) * * NOTE: this file is NOT intended to be included by applications using the * JPEG library. Most applications need only include jpeglib.h. */ /* Include auto-config file to find out which system include files we need. */ #include "jconfig.h" /* auto configuration options */ #define JCONFIG_INCLUDED /* so that jpeglib.h doesn't do it again */ /* * We need the NULL macro and size_t typedef. * On an ANSI-conforming system it is sufficient to include . * Otherwise, we get them from or ; we may have to * pull in as well. * Note that the core JPEG library does not require ; * only the default error handler and data source/destination modules do. * But we must pull it in because of the references to FILE in jpeglib.h. * You can remove those references if you want to compile without . */ #ifdef HAVE_STDDEF_H #include #endif #ifdef HAVE_STDLIB_H #include #endif #ifdef NEED_SYS_TYPES_H #include #endif #include /* * We need memory copying and zeroing functions, plus strncpy(). * ANSI and System V implementations declare these in . * BSD doesn't have the mem() functions, but it does have bcopy()/bzero(). * Some systems may declare memset and memcpy in . * * NOTE: we assume the size parameters to these functions are of type size_t. * Change the casts in these macros if not! */ #ifdef NEED_BSD_STRINGS #include #define MEMZERO(target,size) bzero((void *)(target), (size_t)(size)) #define MEMCOPY(dest,src,size) bcopy((const void *)(src), (void *)(dest), (size_t)(size)) #else /* not BSD, assume ANSI/SysV string lib */ #include #define MEMZERO(target,size) memset((void *)(target), 0, (size_t)(size)) #define MEMCOPY(dest,src,size) memcpy((void *)(dest), (const void *)(src), (size_t)(size)) #endif /* * In ANSI C, and indeed any rational implementation, size_t is also the * type returned by sizeof(). However, it seems there are some irrational * implementations out there, in which sizeof() returns an int even though * size_t is defined as long or unsigned long. To ensure consistent results * we always use this SIZEOF() macro in place of using sizeof() directly. */ #define SIZEOF(object) ((size_t) sizeof(object)) /* * The modules that use fread() and fwrite() always invoke them through * these macros. On some systems you may need to twiddle the argument casts. * CAUTION: argument order is different from underlying functions! */ #define JFREAD(file,buf,sizeofbuf) \ ((size_t) fread((void *) (buf), (size_t) 1, (size_t) (sizeofbuf), (file))) #define JFWRITE(file,buf,sizeofbuf) \ ((size_t) fwrite((const void *) (buf), (size_t) 1, (size_t) (sizeofbuf), (file))) fbi-2.10/jpeg/90/transupp.h0000644000175000017500000002253512506525033013536 0ustar jmmjmm/* * transupp.h * * Copyright (C) 1997-2013, Thomas G. Lane, Guido Vollbeding. * This file is part of the Independent JPEG Group's software. * For conditions of distribution and use, see the accompanying README file. * * This file contains declarations for image transformation routines and * other utility code used by the jpegtran sample application. These are * NOT part of the core JPEG library. But we keep these routines separate * from jpegtran.c to ease the task of maintaining jpegtran-like programs * that have other user interfaces. * * NOTE: all the routines declared here have very specific requirements * about when they are to be executed during the reading and writing of the * source and destination files. See the comments in transupp.c, or see * jpegtran.c for an example of correct usage. */ /* If you happen not to want the image transform support, disable it here */ #ifndef TRANSFORMS_SUPPORTED #define TRANSFORMS_SUPPORTED 1 /* 0 disables transform code */ #endif /* * Although rotating and flipping data expressed as DCT coefficients is not * hard, there is an asymmetry in the JPEG format specification for images * whose dimensions aren't multiples of the iMCU size. The right and bottom * image edges are padded out to the next iMCU boundary with junk data; but * no padding is possible at the top and left edges. If we were to flip * the whole image including the pad data, then pad garbage would become * visible at the top and/or left, and real pixels would disappear into the * pad margins --- perhaps permanently, since encoders & decoders may not * bother to preserve DCT blocks that appear to be completely outside the * nominal image area. So, we have to exclude any partial iMCUs from the * basic transformation. * * Transpose is the only transformation that can handle partial iMCUs at the * right and bottom edges completely cleanly. flip_h can flip partial iMCUs * at the bottom, but leaves any partial iMCUs at the right edge untouched. * Similarly flip_v leaves any partial iMCUs at the bottom edge untouched. * The other transforms are defined as combinations of these basic transforms * and process edge blocks in a way that preserves the equivalence. * * The "trim" option causes untransformable partial iMCUs to be dropped; * this is not strictly lossless, but it usually gives the best-looking * result for odd-size images. Note that when this option is active, * the expected mathematical equivalences between the transforms may not hold. * (For example, -rot 270 -trim trims only the bottom edge, but -rot 90 -trim * followed by -rot 180 -trim trims both edges.) * * We also offer a lossless-crop option, which discards data outside a given * image region but losslessly preserves what is inside. Like the rotate and * flip transforms, lossless crop is restricted by the current JPEG format: the * upper left corner of the selected region must fall on an iMCU boundary. If * this does not hold for the given crop parameters, we silently move the upper * left corner up and/or left to make it so, simultaneously increasing the * region dimensions to keep the lower right crop corner unchanged. (Thus, the * output image covers at least the requested region, but may cover more.) * The adjustment of the region dimensions may be optionally disabled. * * A complementary lossless-wipe option is provided to discard (gray out) data * inside a given image region while losslessly preserving what is outside. * * We also provide a lossless-resize option, which is kind of a lossless-crop * operation in the DCT coefficient block domain - it discards higher-order * coefficients and losslessly preserves lower-order coefficients of a * sub-block. * * Rotate/flip transform, resize, and crop can be requested together in a * single invocation. The crop is applied last --- that is, the crop region * is specified in terms of the destination image after transform/resize. * * We also offer a "force to grayscale" option, which simply discards the * chrominance channels of a YCbCr image. This is lossless in the sense that * the luminance channel is preserved exactly. It's not the same kind of * thing as the rotate/flip transformations, but it's convenient to handle it * as part of this package, mainly because the transformation routines have to * be aware of the option to know how many components to work on. */ /* Short forms of external names for systems with brain-damaged linkers. */ #ifdef NEED_SHORT_EXTERNAL_NAMES #define jtransform_parse_crop_spec jTrParCrop #define jtransform_request_workspace jTrRequest #define jtransform_adjust_parameters jTrAdjust #define jtransform_execute_transform jTrExec #define jtransform_perfect_transform jTrPerfect #define jcopy_markers_setup jCMrkSetup #define jcopy_markers_execute jCMrkExec #endif /* NEED_SHORT_EXTERNAL_NAMES */ /* * Codes for supported types of image transformations. */ typedef enum { JXFORM_NONE, /* no transformation */ JXFORM_FLIP_H, /* horizontal flip */ JXFORM_FLIP_V, /* vertical flip */ JXFORM_TRANSPOSE, /* transpose across UL-to-LR axis */ JXFORM_TRANSVERSE, /* transpose across UR-to-LL axis */ JXFORM_ROT_90, /* 90-degree clockwise rotation */ JXFORM_ROT_180, /* 180-degree rotation */ JXFORM_ROT_270, /* 270-degree clockwise (or 90 ccw) */ JXFORM_WIPE /* wipe */ } JXFORM_CODE; /* * Codes for crop parameters, which can individually be unspecified, * positive or negative for xoffset or yoffset, * positive or forced for width or height. */ typedef enum { JCROP_UNSET, JCROP_POS, JCROP_NEG, JCROP_FORCE } JCROP_CODE; /* * Transform parameters struct. * NB: application must not change any elements of this struct after * calling jtransform_request_workspace. */ typedef struct { /* Options: set by caller */ JXFORM_CODE transform; /* image transform operator */ boolean perfect; /* if TRUE, fail if partial MCUs are requested */ boolean trim; /* if TRUE, trim partial MCUs as needed */ boolean force_grayscale; /* if TRUE, convert color image to grayscale */ boolean crop; /* if TRUE, crop or wipe source image */ /* Crop parameters: application need not set these unless crop is TRUE. * These can be filled in by jtransform_parse_crop_spec(). */ JDIMENSION crop_width; /* Width of selected region */ JCROP_CODE crop_width_set; /* (forced disables adjustment) */ JDIMENSION crop_height; /* Height of selected region */ JCROP_CODE crop_height_set; /* (forced disables adjustment) */ JDIMENSION crop_xoffset; /* X offset of selected region */ JCROP_CODE crop_xoffset_set; /* (negative measures from right edge) */ JDIMENSION crop_yoffset; /* Y offset of selected region */ JCROP_CODE crop_yoffset_set; /* (negative measures from bottom edge) */ /* Internal workspace: caller should not touch these */ int num_components; /* # of components in workspace */ jvirt_barray_ptr * workspace_coef_arrays; /* workspace for transformations */ JDIMENSION output_width; /* cropped destination dimensions */ JDIMENSION output_height; JDIMENSION x_crop_offset; /* destination crop offsets measured in iMCUs */ JDIMENSION y_crop_offset; JDIMENSION drop_width; /* drop/wipe dimensions measured in iMCUs */ JDIMENSION drop_height; int iMCU_sample_width; /* destination iMCU size */ int iMCU_sample_height; } jpeg_transform_info; #if TRANSFORMS_SUPPORTED /* Parse a crop specification (written in X11 geometry style) */ EXTERN(boolean) jtransform_parse_crop_spec JPP((jpeg_transform_info *info, const char *spec)); /* Request any required workspace */ EXTERN(boolean) jtransform_request_workspace JPP((j_decompress_ptr srcinfo, jpeg_transform_info *info)); /* Adjust output image parameters */ EXTERN(jvirt_barray_ptr *) jtransform_adjust_parameters JPP((j_decompress_ptr srcinfo, j_compress_ptr dstinfo, jvirt_barray_ptr *src_coef_arrays, jpeg_transform_info *info)); /* Execute the actual transformation, if any */ EXTERN(void) jtransform_execute_transform JPP((j_decompress_ptr srcinfo, j_compress_ptr dstinfo, jvirt_barray_ptr *src_coef_arrays, jpeg_transform_info *info)); /* Determine whether lossless transformation is perfectly * possible for a specified image and transformation. */ EXTERN(boolean) jtransform_perfect_transform JPP((JDIMENSION image_width, JDIMENSION image_height, int MCU_width, int MCU_height, JXFORM_CODE transform)); /* jtransform_execute_transform used to be called * jtransform_execute_transformation, but some compilers complain about * routine names that long. This macro is here to avoid breaking any * old source code that uses the original name... */ #define jtransform_execute_transformation jtransform_execute_transform #endif /* TRANSFORMS_SUPPORTED */ /* * Support for copying optional markers from source to destination file. */ typedef enum { JCOPYOPT_NONE, /* copy no optional markers */ JCOPYOPT_COMMENTS, /* copy only comment (COM) markers */ JCOPYOPT_ALL /* copy all optional markers */ } JCOPY_OPTION; #define JCOPYOPT_DEFAULT JCOPYOPT_COMMENTS /* recommended default */ /* Setup decompression object to save desired markers in memory */ EXTERN(void) jcopy_markers_setup JPP((j_decompress_ptr srcinfo, JCOPY_OPTION option)); /* Copy markers saved in the given source object to the destination object */ EXTERN(void) jcopy_markers_execute JPP((j_decompress_ptr srcinfo, j_compress_ptr dstinfo, JCOPY_OPTION option)); fbi-2.10/jpeg/90/jpegint.h0000644000175000017500000004160412506525033013320 0ustar jmmjmm/* * jpegint.h * * Copyright (C) 1991-1997, Thomas G. Lane. * Modified 1997-2013 by Guido Vollbeding. * This file is part of the Independent JPEG Group's software. * For conditions of distribution and use, see the accompanying README file. * * This file provides common declarations for the various JPEG modules. * These declarations are considered internal to the JPEG library; most * applications using the library shouldn't need to include this file. */ /* Declarations for both compression & decompression */ typedef enum { /* Operating modes for buffer controllers */ JBUF_PASS_THRU, /* Plain stripwise operation */ /* Remaining modes require a full-image buffer to have been created */ JBUF_SAVE_SOURCE, /* Run source subobject only, save output */ JBUF_CRANK_DEST, /* Run dest subobject only, using saved data */ JBUF_SAVE_AND_PASS /* Run both subobjects, save output */ } J_BUF_MODE; /* Values of global_state field (jdapi.c has some dependencies on ordering!) */ #define CSTATE_START 100 /* after create_compress */ #define CSTATE_SCANNING 101 /* start_compress done, write_scanlines OK */ #define CSTATE_RAW_OK 102 /* start_compress done, write_raw_data OK */ #define CSTATE_WRCOEFS 103 /* jpeg_write_coefficients done */ #define DSTATE_START 200 /* after create_decompress */ #define DSTATE_INHEADER 201 /* reading header markers, no SOS yet */ #define DSTATE_READY 202 /* found SOS, ready for start_decompress */ #define DSTATE_PRELOAD 203 /* reading multiscan file in start_decompress*/ #define DSTATE_PRESCAN 204 /* performing dummy pass for 2-pass quant */ #define DSTATE_SCANNING 205 /* start_decompress done, read_scanlines OK */ #define DSTATE_RAW_OK 206 /* start_decompress done, read_raw_data OK */ #define DSTATE_BUFIMAGE 207 /* expecting jpeg_start_output */ #define DSTATE_BUFPOST 208 /* looking for SOS/EOI in jpeg_finish_output */ #define DSTATE_RDCOEFS 209 /* reading file in jpeg_read_coefficients */ #define DSTATE_STOPPING 210 /* looking for EOI in jpeg_finish_decompress */ /* Declarations for compression modules */ /* Master control module */ struct jpeg_comp_master { JMETHOD(void, prepare_for_pass, (j_compress_ptr cinfo)); JMETHOD(void, pass_startup, (j_compress_ptr cinfo)); JMETHOD(void, finish_pass, (j_compress_ptr cinfo)); /* State variables made visible to other modules */ boolean call_pass_startup; /* True if pass_startup must be called */ boolean is_last_pass; /* True during last pass */ }; /* Main buffer control (downsampled-data buffer) */ struct jpeg_c_main_controller { JMETHOD(void, start_pass, (j_compress_ptr cinfo, J_BUF_MODE pass_mode)); JMETHOD(void, process_data, (j_compress_ptr cinfo, JSAMPARRAY input_buf, JDIMENSION *in_row_ctr, JDIMENSION in_rows_avail)); }; /* Compression preprocessing (downsampling input buffer control) */ struct jpeg_c_prep_controller { JMETHOD(void, start_pass, (j_compress_ptr cinfo, J_BUF_MODE pass_mode)); JMETHOD(void, pre_process_data, (j_compress_ptr cinfo, JSAMPARRAY input_buf, JDIMENSION *in_row_ctr, JDIMENSION in_rows_avail, JSAMPIMAGE output_buf, JDIMENSION *out_row_group_ctr, JDIMENSION out_row_groups_avail)); }; /* Coefficient buffer control */ struct jpeg_c_coef_controller { JMETHOD(void, start_pass, (j_compress_ptr cinfo, J_BUF_MODE pass_mode)); JMETHOD(boolean, compress_data, (j_compress_ptr cinfo, JSAMPIMAGE input_buf)); }; /* Colorspace conversion */ struct jpeg_color_converter { JMETHOD(void, start_pass, (j_compress_ptr cinfo)); JMETHOD(void, color_convert, (j_compress_ptr cinfo, JSAMPARRAY input_buf, JSAMPIMAGE output_buf, JDIMENSION output_row, int num_rows)); }; /* Downsampling */ struct jpeg_downsampler { JMETHOD(void, start_pass, (j_compress_ptr cinfo)); JMETHOD(void, downsample, (j_compress_ptr cinfo, JSAMPIMAGE input_buf, JDIMENSION in_row_index, JSAMPIMAGE output_buf, JDIMENSION out_row_group_index)); boolean need_context_rows; /* TRUE if need rows above & below */ }; /* Forward DCT (also controls coefficient quantization) */ typedef JMETHOD(void, forward_DCT_ptr, (j_compress_ptr cinfo, jpeg_component_info * compptr, JSAMPARRAY sample_data, JBLOCKROW coef_blocks, JDIMENSION start_row, JDIMENSION start_col, JDIMENSION num_blocks)); struct jpeg_forward_dct { JMETHOD(void, start_pass, (j_compress_ptr cinfo)); /* It is useful to allow each component to have a separate FDCT method. */ forward_DCT_ptr forward_DCT[MAX_COMPONENTS]; }; /* Entropy encoding */ struct jpeg_entropy_encoder { JMETHOD(void, start_pass, (j_compress_ptr cinfo, boolean gather_statistics)); JMETHOD(boolean, encode_mcu, (j_compress_ptr cinfo, JBLOCKROW *MCU_data)); JMETHOD(void, finish_pass, (j_compress_ptr cinfo)); }; /* Marker writing */ struct jpeg_marker_writer { JMETHOD(void, write_file_header, (j_compress_ptr cinfo)); JMETHOD(void, write_frame_header, (j_compress_ptr cinfo)); JMETHOD(void, write_scan_header, (j_compress_ptr cinfo)); JMETHOD(void, write_file_trailer, (j_compress_ptr cinfo)); JMETHOD(void, write_tables_only, (j_compress_ptr cinfo)); /* These routines are exported to allow insertion of extra markers */ /* Probably only COM and APPn markers should be written this way */ JMETHOD(void, write_marker_header, (j_compress_ptr cinfo, int marker, unsigned int datalen)); JMETHOD(void, write_marker_byte, (j_compress_ptr cinfo, int val)); }; /* Declarations for decompression modules */ /* Master control module */ struct jpeg_decomp_master { JMETHOD(void, prepare_for_output_pass, (j_decompress_ptr cinfo)); JMETHOD(void, finish_output_pass, (j_decompress_ptr cinfo)); /* State variables made visible to other modules */ boolean is_dummy_pass; /* True during 1st pass for 2-pass quant */ }; /* Input control module */ struct jpeg_input_controller { JMETHOD(int, consume_input, (j_decompress_ptr cinfo)); JMETHOD(void, reset_input_controller, (j_decompress_ptr cinfo)); JMETHOD(void, start_input_pass, (j_decompress_ptr cinfo)); JMETHOD(void, finish_input_pass, (j_decompress_ptr cinfo)); /* State variables made visible to other modules */ boolean has_multiple_scans; /* True if file has multiple scans */ boolean eoi_reached; /* True when EOI has been consumed */ }; /* Main buffer control (downsampled-data buffer) */ struct jpeg_d_main_controller { JMETHOD(void, start_pass, (j_decompress_ptr cinfo, J_BUF_MODE pass_mode)); JMETHOD(void, process_data, (j_decompress_ptr cinfo, JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, JDIMENSION out_rows_avail)); }; /* Coefficient buffer control */ struct jpeg_d_coef_controller { JMETHOD(void, start_input_pass, (j_decompress_ptr cinfo)); JMETHOD(int, consume_data, (j_decompress_ptr cinfo)); JMETHOD(void, start_output_pass, (j_decompress_ptr cinfo)); JMETHOD(int, decompress_data, (j_decompress_ptr cinfo, JSAMPIMAGE output_buf)); /* Pointer to array of coefficient virtual arrays, or NULL if none */ jvirt_barray_ptr *coef_arrays; }; /* Decompression postprocessing (color quantization buffer control) */ struct jpeg_d_post_controller { JMETHOD(void, start_pass, (j_decompress_ptr cinfo, J_BUF_MODE pass_mode)); JMETHOD(void, post_process_data, (j_decompress_ptr cinfo, JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr, JDIMENSION in_row_groups_avail, JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, JDIMENSION out_rows_avail)); }; /* Marker reading & parsing */ struct jpeg_marker_reader { JMETHOD(void, reset_marker_reader, (j_decompress_ptr cinfo)); /* Read markers until SOS or EOI. * Returns same codes as are defined for jpeg_consume_input: * JPEG_SUSPENDED, JPEG_REACHED_SOS, or JPEG_REACHED_EOI. */ JMETHOD(int, read_markers, (j_decompress_ptr cinfo)); /* Read a restart marker --- exported for use by entropy decoder only */ jpeg_marker_parser_method read_restart_marker; /* State of marker reader --- nominally internal, but applications * supplying COM or APPn handlers might like to know the state. */ boolean saw_SOI; /* found SOI? */ boolean saw_SOF; /* found SOF? */ int next_restart_num; /* next restart number expected (0-7) */ unsigned int discarded_bytes; /* # of bytes skipped looking for a marker */ }; /* Entropy decoding */ struct jpeg_entropy_decoder { JMETHOD(void, start_pass, (j_decompress_ptr cinfo)); JMETHOD(boolean, decode_mcu, (j_decompress_ptr cinfo, JBLOCKROW *MCU_data)); JMETHOD(void, finish_pass, (j_decompress_ptr cinfo)); }; /* Inverse DCT (also performs dequantization) */ typedef JMETHOD(void, inverse_DCT_method_ptr, (j_decompress_ptr cinfo, jpeg_component_info * compptr, JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); struct jpeg_inverse_dct { JMETHOD(void, start_pass, (j_decompress_ptr cinfo)); /* It is useful to allow each component to have a separate IDCT method. */ inverse_DCT_method_ptr inverse_DCT[MAX_COMPONENTS]; }; /* Upsampling (note that upsampler must also call color converter) */ struct jpeg_upsampler { JMETHOD(void, start_pass, (j_decompress_ptr cinfo)); JMETHOD(void, upsample, (j_decompress_ptr cinfo, JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr, JDIMENSION in_row_groups_avail, JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, JDIMENSION out_rows_avail)); boolean need_context_rows; /* TRUE if need rows above & below */ }; /* Colorspace conversion */ struct jpeg_color_deconverter { JMETHOD(void, start_pass, (j_decompress_ptr cinfo)); JMETHOD(void, color_convert, (j_decompress_ptr cinfo, JSAMPIMAGE input_buf, JDIMENSION input_row, JSAMPARRAY output_buf, int num_rows)); }; /* Color quantization or color precision reduction */ struct jpeg_color_quantizer { JMETHOD(void, start_pass, (j_decompress_ptr cinfo, boolean is_pre_scan)); JMETHOD(void, color_quantize, (j_decompress_ptr cinfo, JSAMPARRAY input_buf, JSAMPARRAY output_buf, int num_rows)); JMETHOD(void, finish_pass, (j_decompress_ptr cinfo)); JMETHOD(void, new_color_map, (j_decompress_ptr cinfo)); }; /* Miscellaneous useful macros */ #undef MAX #define MAX(a,b) ((a) > (b) ? (a) : (b)) #undef MIN #define MIN(a,b) ((a) < (b) ? (a) : (b)) /* We assume that right shift corresponds to signed division by 2 with * rounding towards minus infinity. This is correct for typical "arithmetic * shift" instructions that shift in copies of the sign bit. But some * C compilers implement >> with an unsigned shift. For these machines you * must define RIGHT_SHIFT_IS_UNSIGNED. * RIGHT_SHIFT provides a proper signed right shift of an INT32 quantity. * It is only applied with constant shift counts. SHIFT_TEMPS must be * included in the variables of any routine using RIGHT_SHIFT. */ #ifdef RIGHT_SHIFT_IS_UNSIGNED #define SHIFT_TEMPS INT32 shift_temp; #define RIGHT_SHIFT(x,shft) \ ((shift_temp = (x)) < 0 ? \ (shift_temp >> (shft)) | ((~((INT32) 0)) << (32-(shft))) : \ (shift_temp >> (shft))) #else #define SHIFT_TEMPS #define RIGHT_SHIFT(x,shft) ((x) >> (shft)) #endif /* Short forms of external names for systems with brain-damaged linkers. */ #ifdef NEED_SHORT_EXTERNAL_NAMES #define jinit_compress_master jICompress #define jinit_c_master_control jICMaster #define jinit_c_main_controller jICMainC #define jinit_c_prep_controller jICPrepC #define jinit_c_coef_controller jICCoefC #define jinit_color_converter jICColor #define jinit_downsampler jIDownsampler #define jinit_forward_dct jIFDCT #define jinit_huff_encoder jIHEncoder #define jinit_arith_encoder jIAEncoder #define jinit_marker_writer jIMWriter #define jinit_master_decompress jIDMaster #define jinit_d_main_controller jIDMainC #define jinit_d_coef_controller jIDCoefC #define jinit_d_post_controller jIDPostC #define jinit_input_controller jIInCtlr #define jinit_marker_reader jIMReader #define jinit_huff_decoder jIHDecoder #define jinit_arith_decoder jIADecoder #define jinit_inverse_dct jIIDCT #define jinit_upsampler jIUpsampler #define jinit_color_deconverter jIDColor #define jinit_1pass_quantizer jI1Quant #define jinit_2pass_quantizer jI2Quant #define jinit_merged_upsampler jIMUpsampler #define jinit_memory_mgr jIMemMgr #define jdiv_round_up jDivRound #define jround_up jRound #define jzero_far jZeroFar #define jcopy_sample_rows jCopySamples #define jcopy_block_row jCopyBlocks #define jpeg_zigzag_order jZIGTable #define jpeg_natural_order jZAGTable #define jpeg_natural_order7 jZAG7Table #define jpeg_natural_order6 jZAG6Table #define jpeg_natural_order5 jZAG5Table #define jpeg_natural_order4 jZAG4Table #define jpeg_natural_order3 jZAG3Table #define jpeg_natural_order2 jZAG2Table #define jpeg_aritab jAriTab #endif /* NEED_SHORT_EXTERNAL_NAMES */ /* On normal machines we can apply MEMCOPY() and MEMZERO() to sample arrays * and coefficient-block arrays. This won't work on 80x86 because the arrays * are FAR and we're assuming a small-pointer memory model. However, some * DOS compilers provide far-pointer versions of memcpy() and memset() even * in the small-model libraries. These will be used if USE_FMEM is defined. * Otherwise, the routines in jutils.c do it the hard way. */ #ifndef NEED_FAR_POINTERS /* normal case, same as regular macro */ #define FMEMZERO(target,size) MEMZERO(target,size) #else /* 80x86 case */ #ifdef USE_FMEM #define FMEMZERO(target,size) _fmemset((void FAR *)(target), 0, (size_t)(size)) #else EXTERN(void) jzero_far JPP((void FAR * target, size_t bytestozero)); #define FMEMZERO(target,size) jzero_far(target, size) #endif #endif /* Compression module initialization routines */ EXTERN(void) jinit_compress_master JPP((j_compress_ptr cinfo)); EXTERN(void) jinit_c_master_control JPP((j_compress_ptr cinfo, boolean transcode_only)); EXTERN(void) jinit_c_main_controller JPP((j_compress_ptr cinfo, boolean need_full_buffer)); EXTERN(void) jinit_c_prep_controller JPP((j_compress_ptr cinfo, boolean need_full_buffer)); EXTERN(void) jinit_c_coef_controller JPP((j_compress_ptr cinfo, boolean need_full_buffer)); EXTERN(void) jinit_color_converter JPP((j_compress_ptr cinfo)); EXTERN(void) jinit_downsampler JPP((j_compress_ptr cinfo)); EXTERN(void) jinit_forward_dct JPP((j_compress_ptr cinfo)); EXTERN(void) jinit_huff_encoder JPP((j_compress_ptr cinfo)); EXTERN(void) jinit_arith_encoder JPP((j_compress_ptr cinfo)); EXTERN(void) jinit_marker_writer JPP((j_compress_ptr cinfo)); /* Decompression module initialization routines */ EXTERN(void) jinit_master_decompress JPP((j_decompress_ptr cinfo)); EXTERN(void) jinit_d_main_controller JPP((j_decompress_ptr cinfo, boolean need_full_buffer)); EXTERN(void) jinit_d_coef_controller JPP((j_decompress_ptr cinfo, boolean need_full_buffer)); EXTERN(void) jinit_d_post_controller JPP((j_decompress_ptr cinfo, boolean need_full_buffer)); EXTERN(void) jinit_input_controller JPP((j_decompress_ptr cinfo)); EXTERN(void) jinit_marker_reader JPP((j_decompress_ptr cinfo)); EXTERN(void) jinit_huff_decoder JPP((j_decompress_ptr cinfo)); EXTERN(void) jinit_arith_decoder JPP((j_decompress_ptr cinfo)); EXTERN(void) jinit_inverse_dct JPP((j_decompress_ptr cinfo)); EXTERN(void) jinit_upsampler JPP((j_decompress_ptr cinfo)); EXTERN(void) jinit_color_deconverter JPP((j_decompress_ptr cinfo)); EXTERN(void) jinit_1pass_quantizer JPP((j_decompress_ptr cinfo)); EXTERN(void) jinit_2pass_quantizer JPP((j_decompress_ptr cinfo)); EXTERN(void) jinit_merged_upsampler JPP((j_decompress_ptr cinfo)); /* Memory manager initialization */ EXTERN(void) jinit_memory_mgr JPP((j_common_ptr cinfo)); /* Utility routines in jutils.c */ EXTERN(long) jdiv_round_up JPP((long a, long b)); EXTERN(long) jround_up JPP((long a, long b)); EXTERN(void) jcopy_sample_rows JPP((JSAMPARRAY input_array, int source_row, JSAMPARRAY output_array, int dest_row, int num_rows, JDIMENSION num_cols)); EXTERN(void) jcopy_block_row JPP((JBLOCKROW input_row, JBLOCKROW output_row, JDIMENSION num_blocks)); /* Constant tables in jutils.c */ #if 0 /* This table is not actually needed in v6a */ extern const int jpeg_zigzag_order[]; /* natural coef order to zigzag order */ #endif extern const int jpeg_natural_order[]; /* zigzag coef order to natural order */ extern const int jpeg_natural_order7[]; /* zz to natural order for 7x7 block */ extern const int jpeg_natural_order6[]; /* zz to natural order for 6x6 block */ extern const int jpeg_natural_order5[]; /* zz to natural order for 5x5 block */ extern const int jpeg_natural_order4[]; /* zz to natural order for 4x4 block */ extern const int jpeg_natural_order3[]; /* zz to natural order for 3x3 block */ extern const int jpeg_natural_order2[]; /* zz to natural order for 2x2 block */ /* Arithmetic coding probability estimation tables in jaricom.c */ extern const INT32 jpeg_aritab[]; /* Suppress undefined-structure complaints if necessary. */ #ifdef INCOMPLETE_TYPES_BROKEN #ifndef AM_MEMORY_MANAGER /* only jmemmgr.c defines these */ struct jvirt_sarray_control { long dummy; }; struct jvirt_barray_control { long dummy; }; #endif #endif /* INCOMPLETE_TYPES_BROKEN */ fbi-2.10/jpegtools.h0000644000175000017500000000155012506525033012505 0ustar jmmjmm /* various flags */ #define JFLAG_TRANSFORM_IMAGE 0x0001 #define JFLAG_TRANSFORM_THUMBNAIL 0x0002 #define JFLAG_TRANSFORM_TRIM 0x0004 #define JFLAG_UPDATE_COMMENT 0x0010 #define JFLAG_UPDATE_ORIENTATION 0x0020 #define JFLAG_UPDATE_THUMBNAIL 0x0040 #define JFLAG_FILE_BACKUP 0x0100 #define JFLAG_FILE_KEEP_TIME 0x0200 /* functions */ int jpeg_transform_fp(FILE *in, FILE *out, JXFORM_CODE transform, unsigned char *comment, char *thumbnail, int tsize, unsigned int flags); int jpeg_transform_files(char *infile, char *outfile, JXFORM_CODE transform, unsigned char *comment, char *thumbnail, int tsize, unsigned int flags); int jpeg_transform_inplace(char *file, JXFORM_CODE transform, unsigned char *comment, char *thumbnail, int tsize, unsigned int flags); fbi-2.10/mallard_16.xpm0000644000175000017500000000104712506525033012777 0ustar jmmjmm/* XPM */ static char * mallard_small_xpm[] = { "16 16 8 1", " c #B9B9C1C1E2E2", ". c #000032321010", "X c #121284843131", "o c #FFFFFFFF0000", "O c #FFFFFFFFFFFF", "+ c #1F1F13131313", "@ c #000000000000", "# c #79792B2B1717", " ", " ", " ", " .. ", " ..X. ", " ooXX. ", "oo ... ", " OOO++++++ @ ", " +++O+OOOO++@@ ", " +++OOO+O++++@OO", " +++OOOOOOOOO ", " +++OOOO # ", " # ", " ## ", " ", " "}; fbi-2.10/rd/0000755000175000017500000000000012506525033010732 5ustar jmmjmmfbi-2.10/rd/read-xpm.c0000644000175000017500000001446712506525033012627 0ustar jmmjmm#include #include #include #include #include #include #include #include "ida.h" #include "readers.h" #include "viewer.h" /* ---------------------------------------------------------------------- */ /* load */ struct xpm_color { char name[8]; XColor color; }; struct xpm_state { FILE *infile; int width,height,colors,chars; struct xpm_color *cmap; char *charline; char *rgbrow; }; static void* xpm_init(FILE *fp, char *filename, unsigned int page, struct ida_image_info *info, int thumbnail) { struct xpm_state *h; char line[1024],cname[32],*tmp; XColor dummy; int i; Colormap cmap = DefaultColormapOfScreen(XtScreen(app_shell)); h = malloc(sizeof(*h)); memset(h,0,sizeof(*h)); h->infile = fp; fgets(line,sizeof(line)-1,fp); /* XPM */ fgets(line,sizeof(line)-1,fp); /* static char ... */ while (0 == strncmp(line,"/*",2)) { while (NULL == strstr(line,"*/")) fgets(line,sizeof(line)-1,fp); fgets(line,sizeof(line)-1,fp); } /* size, colors */ fgets(line,sizeof(line)-1,fp); if (0 == strncmp(line,"/*",2)) { while (NULL == strstr(line,"*/")) fgets(line,sizeof(line)-1,fp); fgets(line,sizeof(line)-1,fp); } if (4 != sscanf(line,"\"%d %d %d %d", &h->width,&h->height,&h->colors,&h->chars)) goto oops; if (h->chars > 7) goto oops; /* read color table */ h->cmap = malloc(h->colors * sizeof(struct xpm_color)); memset(h->cmap,0,h->colors * sizeof(struct xpm_color)); for (i = 0; i < h->colors; i++) { fgets(line,sizeof(line)-1,fp); while (0 == strncmp(line,"/*",2)) { while (NULL == strstr(line,"*/")) fgets(line,sizeof(line)-1,fp); fgets(line,sizeof(line)-1,fp); } memcpy(h->cmap[i].name,line+1,h->chars); if (NULL != (tmp = strstr(line+1+h->chars,"c "))) { /* color */ sscanf(tmp+2,"%32[^\" ]",cname); } else if (NULL != (tmp = strstr(line+h->chars,"m "))) { /* mono */ sscanf(tmp+2,"%32[^\" ]",cname); } else if (NULL != (tmp = strstr(line+h->chars,"g "))) { /* gray? */ sscanf(tmp+2,"%32[^\" ]",cname); } else goto oops; if (0 == strcasecmp(cname,"none")) /* transparent */ strcpy(cname,"lightgray"); if (debug) fprintf(stderr,"xpm: cmap: \"%*.*s\" => %s\n", h->chars,h->chars,h->cmap[i].name,cname); #if 0 if (1 != sscanf(line+1+h->chars," c %32[^\"]",cname)) goto oops; #endif XLookupColor(dpy,cmap,cname,&h->cmap[i].color,&dummy); } h->charline = malloc(h->width * h->chars + 8); h->rgbrow = malloc(h->width * 3); info->width = h->width; info->height = h->height; info->npages = 1; return h; oops: fclose(fp); free(h); return NULL; } static void xpm_read(unsigned char *dst, unsigned int line, void *data) { struct xpm_state *h = data; char *src; int i,c; fgets(h->charline,h->width * h->chars + 8,h->infile); while (0 == strncmp(h->charline,"/*",2)) { while (NULL == strstr(h->charline,"*/")) fgets(h->charline,h->width * h->chars + 8,h->infile); fgets(h->charline,h->width * h->chars + 8,h->infile); } src = h->charline+1; for (i = 0; i < h->width; i++) { for (c = 0; c < h->colors; c++) { char *name = h->cmap[c].name; if (src[0] != name[0]) continue; if (1 == h->chars) break; if (src[1] != name[1]) continue; if (2 == h->chars) break; if (0 == strncmp(src+2,name+2,h->chars-2)) break; } if (c == h->colors) continue; dst[0] = h->cmap[c].color.red >> 8; dst[1] = h->cmap[c].color.green >> 8; dst[2] = h->cmap[c].color.blue >> 8; src += h->chars; dst += 3; } } static void xpm_done(void *data) { struct xpm_state *h = data; fclose(h->infile); free(h->charline); free(h->rgbrow); free(h->cmap); free(h); } /* ---------------------------------------------------------------------- */ struct xbm_state { FILE *infile; int width,height; }; static void* xbm_init(FILE *fp, char *filename, unsigned int page, struct ida_image_info *info, int thumbnail) { struct xbm_state *h; char line[256],dummy[128]; int i; h = malloc(sizeof(*h)); memset(h,0,sizeof(*h)); h->infile = fp; for (i = 0; i < 128; i++) { fgets(line,sizeof(line)-1,fp); if (0 == strncmp(line,"#define",7)) break; } if (128 == i) goto oops; if (2 != sscanf(line,"#define %127s %d",dummy,&h->width)) goto oops; fgets(line,sizeof(line)-1,fp); if (2 != sscanf(line,"#define %127s %d",dummy,&h->height)) goto oops; if (debug) fprintf(stderr,"xbm: %dx%d\n",h->width,h->height); for (i = 0; i < 4; i++) { fgets(line,sizeof(line)-1,fp); if (strstr(line,"[] = {")) break; } if (4 == i) goto oops; info->width = h->width; info->height = h->height; info->npages = 1; return h; oops: if (debug) fprintf(stderr,"xbm: %s",line); fclose(fp); free(h); return NULL; } static void xbm_read(unsigned char *dst, unsigned int line, void *data) { struct xbm_state *h = data; int x,val; for (x = 0; x < h->width; x++) { if (0 == (x % 8)) fscanf(h->infile," 0x%x,",&val); if (val & (1 << (x % 8))) { *(dst++) = 0; *(dst++) = 0; *(dst++) = 0; } else { *(dst++) = 255; *(dst++) = 255; *(dst++) = 255; } } } static void xbm_done(void *data) { struct xpm_state *h = data; fclose(h->infile); free(h); } /* ---------------------------------------------------------------------- */ static struct ida_loader xpm_loader = { magic: "/* XPM */", moff: 0, mlen: 9, name: "xpm parser", init: xpm_init, read: xpm_read, done: xpm_done, }; static struct ida_loader xbm1_loader = { magic: "#define", moff: 0, mlen: 7, name: "xbm parser", init: xbm_init, read: xbm_read, done: xbm_done, }; static struct ida_loader xbm2_loader = { magic: "/*", moff: 0, mlen: 2, name: "xbm parser", init: xbm_init, read: xbm_read, done: xbm_done, }; static void __init init_rd(void) { load_register(&xpm_loader); load_register(&xbm1_loader); load_register(&xbm2_loader); } fbi-2.10/rd/Makefile0000644000175000017500000000003112506525033012364 0ustar jmmjmmdefault: cd ..; $(MAKE) fbi-2.10/rd/read-webp.c0000644000175000017500000000256212506525033012751 0ustar jmmjmm#include #include #include #include #include #include "readers.h" struct webp_state { FILE *f; int width, height; uint8_t *data; }; static void * webp_init(FILE *fp, char *filename, unsigned int page, struct ida_image_info *i, int thumbnail) { uint32_t img_size; void *img; struct webp_state *h; h = malloc(sizeof(*h)); h->f = fp; if(fseek(fp, 0, SEEK_END) != 0) { free(h); return NULL; } img_size = ftell(fp); img = malloc(img_size); if(fseek(fp, 0, SEEK_SET) != 0) { free(img); free(h); return NULL; } if(fread(img, img_size, 1, fp) != 1) { free(img); free(h); return NULL; } h->data = WebPDecodeRGBA(img, img_size, &h->width, &h->height); i->width = h->width; i->height = h->height; i->dpi = 100; i->npages = 1; free(img); return h; } static void webp_read(unsigned char *dst, unsigned int line, void *data) { struct webp_state *h = data; load_rgba(dst, h->data + line * 4 * h->width, h->width); } static void webp_done(void *data) { struct webp_state *h = data; free(h->data); fclose(h->f); free(h); } static struct ida_loader webp_loader = { magic: "WEBPVP8", moff: 8, mlen: 7, name: "libwebp", init: webp_init, read: webp_read, done: webp_done, }; static void __init init_rd(void) { load_register(&webp_loader); } fbi-2.10/rd/read-ppm.c0000644000175000017500000000515412506525033012610 0ustar jmmjmm#include #include #include #include #include #include "readers.h" /* ---------------------------------------------------------------------- */ /* load */ struct ppm_state { FILE *infile; int width,height; unsigned char *row; }; static void* pnm_init(FILE *fp, char *filename, unsigned int page, struct ida_image_info *i, int thumbnail) { struct ppm_state *h; char line[1024]; char p; h = malloc(sizeof(*h)); memset(h,0,sizeof(*h)); h->infile = fp; fgets(line,sizeof(line),fp); /* P[456] */ p = line[1]; fgets(line,sizeof(line),fp); /* width height */ while ('#' == line[0]) fgets(line,sizeof(line),fp); /* skip comments */ sscanf(line,"%d %d",&h->width,&h->height); if (p != '4') fgets(line,sizeof(line),fp); /* depth ??? */ if (0 == h->width || 0 == h->height) goto oops; i->width = h->width; i->height = h->height; i->npages = 1; h->row = malloc(h->width*3); return h; oops: fclose(fp); free(h); return NULL; } static void ppm_read(unsigned char *dst, unsigned int line, void *data) { struct ppm_state *h = data; fread(dst,h->width,3,h->infile); } static void pgm_read(unsigned char *dst, unsigned int line, void *data) { struct ppm_state *h = data; unsigned char *src; int x; fread(h->row,h->width,1,h->infile); src = h->row; for (x = 0; x < h->width; x++) { dst[0] = src[0]; dst[1] = src[0]; dst[2] = src[0]; dst += 3; src += 1; } } static void pbm_read(unsigned char *dst, unsigned int line, void *data) { struct ppm_state *h = data; int bpl; bpl = ((h->width+7) >> 3); fread(h->row,bpl,1,h->infile); load_bits_msb(dst,(unsigned char*)(h->row),h->width,0,255); } static void pnm_done(void *data) { struct ppm_state *h = data; fclose(h->infile); free(h->row); free(h); } struct ida_loader ppm_loader = { magic: "P6", moff: 0, mlen: 2, name: "ppm parser", init: pnm_init, read: ppm_read, done: pnm_done, }; static struct ida_loader pgm_loader = { magic: "P5", moff: 0, mlen: 2, name: "pgm parser", init: pnm_init, read: pgm_read, done: pnm_done, }; static struct ida_loader pbm_loader = { magic: "P4", moff: 0, mlen: 2, name: "pbm parser", init: pnm_init, read: pbm_read, done: pnm_done, }; static void __init init_rd(void) { load_register(&ppm_loader); load_register(&pgm_loader); load_register(&pbm_loader); } fbi-2.10/rd/read-gif.c0000644000175000017500000001304112506525033012553 0ustar jmmjmm#include #include #include #include #include #include "readers.h" #if defined(GIFLIB_MAJOR) && (GIFLIB_MAJOR >= 5) #define GIF5DATA(e) e static void PrintGifError(int err) { fprintf(stderr, "GIF library error: %s\n", GifErrorString(err)); } #else #define GIF5DATA(x) #define PrintGifError(e) PrintGifError() #define DGifOpenFileHandle(x,e) DGifOpenFileHandle(x) #define DGifCloseFile(x,e) DGifCloseFile(x) #endif struct gif_state { FILE *infile; GifFileType *gif; GifPixelType *row; GifPixelType *il; int w,h; }; static GifRecordType gif_fileread(struct gif_state *h) { GifRecordType RecordType; GifByteType *Extension; int ExtCode, rc; char *type; for (;;) { if (GIF_ERROR == DGifGetRecordType(h->gif,&RecordType)) { if (debug) fprintf(stderr,"gif: DGifGetRecordType failed\n"); PrintGifError(h->gif->Error); return -1; } switch (RecordType) { case IMAGE_DESC_RECORD_TYPE: if (debug) fprintf(stderr,"gif: IMAGE_DESC_RECORD_TYPE found\n"); return RecordType; case EXTENSION_RECORD_TYPE: if (debug) fprintf(stderr,"gif: EXTENSION_RECORD_TYPE found\n"); for (rc = DGifGetExtension(h->gif,&ExtCode,&Extension); NULL != Extension; rc = DGifGetExtensionNext(h->gif,&Extension)) { if (rc == GIF_ERROR) { if (debug) fprintf(stderr,"gif: DGifGetExtension failed\n"); PrintGifError(h->gif->Error); return -1; } if (debug) { switch (ExtCode) { case COMMENT_EXT_FUNC_CODE: type="comment"; break; case GRAPHICS_EXT_FUNC_CODE: type="graphics"; break; case PLAINTEXT_EXT_FUNC_CODE: type="plaintext"; break; case APPLICATION_EXT_FUNC_CODE: type="appl"; break; default: type="???"; break; } fprintf(stderr,"gif: extcode=0x%x [%s]\n",ExtCode,type); } } break; case TERMINATE_RECORD_TYPE: if (debug) fprintf(stderr,"gif: TERMINATE_RECORD_TYPE found\n"); return RecordType; default: if (debug) fprintf(stderr,"gif: unknown record type [%d]\n",RecordType); return -1; } } } #if 0 static void gif_skipimage(struct gif_state *h) { unsigned char *line; int i; if (debug) fprintf(stderr,"gif: skipping image record ...\n"); DGifGetImageDesc(h->gif); line = malloc(h->gif->SWidth); for (i = 0; i < h->gif->SHeight; i++) DGifGetLine(h->gif, line, h->gif->SWidth); free(line); } #endif static void* gif_init(FILE *fp, char *filename, unsigned int page, struct ida_image_info *info, int thumbnail) { struct gif_state *h; GifRecordType RecordType; int i, image = 0; GIF5DATA(int giferror = 0;) h = malloc(sizeof(*h)); memset(h,0,sizeof(*h)); h->infile = fp; h->gif = DGifOpenFileHandle(fileno(fp), &giferror); h->row = malloc(h->gif->SWidth * sizeof(GifPixelType)); while (0 == image) { RecordType = gif_fileread(h); switch (RecordType) { case IMAGE_DESC_RECORD_TYPE: if (GIF_ERROR == DGifGetImageDesc(h->gif)) { if (debug) fprintf(stderr,"gif: DGifGetImageDesc failed\n"); PrintGifError(giferror); } if (NULL == h->gif->SColorMap && NULL == h->gif->Image.ColorMap) { if (debug) fprintf(stderr,"gif: oops: no colormap found\n"); goto oops; } #if 0 info->width = h->w = h->gif->SWidth; info->height = h->h = h->gif->SHeight; #else info->width = h->w = h->gif->Image.Width; info->height = h->h = h->gif->Image.Height; #endif info->npages = 1; image = 1; if (debug) fprintf(stderr,"gif: reading image record ...\n"); if (h->gif->Image.Interlace) { if (debug) fprintf(stderr,"gif: interlaced\n"); h->il = malloc(h->w * h->h * sizeof(GifPixelType)); for (i = 0; i < h->h; i += 8) DGifGetLine(h->gif, h->il + h->w*i,h->w); for (i = 4; i < h->gif->SHeight; i += 8) DGifGetLine(h->gif, h->il + h->w*i,h->w); for (i = 2; i < h->gif->SHeight; i += 4) DGifGetLine(h->gif, h->il + h->w*i,h->w); } break; case TERMINATE_RECORD_TYPE: default: goto oops; } } if (0 == info->width || 0 == info->height) goto oops; if (debug) fprintf(stderr,"gif: s=%dx%d i=%dx%d\n", h->gif->SWidth,h->gif->SHeight, h->gif->Image.Width,h->gif->Image.Height); return h; oops: if (debug) fprintf(stderr,"gif: fatal error, aborting\n"); DGifCloseFile(h->gif, NULL); fclose(h->infile); free(h->row); free(h); return NULL; } static void gif_read(unsigned char *dst, unsigned int line, void *data) { struct gif_state *h = data; GifColorType *cmap; int x; if (h->gif->Image.Interlace) { if (line % 2) { DGifGetLine(h->gif, h->row, h->w); } else { memcpy(h->row, h->il + h->w * line, h->w); } } else { DGifGetLine(h->gif, h->row, h->w); } cmap = h->gif->Image.ColorMap ? h->gif->Image.ColorMap->Colors : h->gif->SColorMap->Colors; for (x = 0; x < h->w; x++) { dst[0] = cmap[h->row[x]].Red; dst[1] = cmap[h->row[x]].Green; dst[2] = cmap[h->row[x]].Blue; dst += 3; } } static void gif_done(void *data) { struct gif_state *h = data; if (debug) fprintf(stderr,"gif: done, cleaning up\n"); DGifCloseFile(h->gif, NULL); fclose(h->infile); if (h->il) free(h->il); free(h->row); free(h); } static struct ida_loader gif_loader = { magic: "GIF", moff: 0, mlen: 3, name: "giflib", init: gif_init, read: gif_read, done: gif_done, }; static void __init init_rd(void) { load_register(&gif_loader); } fbi-2.10/rd/read-pcd.c0000644000175000017500000000310412506525033012553 0ustar jmmjmm#include #include #include #include #include #include "pcd.h" #include "readers.h" extern int pcd_res; /* ---------------------------------------------------------------------- */ /* load */ struct pcd_state { struct PCD_IMAGE img; int left,top,width,height; }; static void* pcd_init(FILE *fp, char *filename, unsigned int page, struct ida_image_info *i, int thumbnail) { struct pcd_state *h; fclose(fp); h = malloc(sizeof(*h)); memset(h,0,sizeof(*h)); if (0 != pcd_open(&h->img, filename)) goto oops; if (-1 == pcd_select(&h->img, thumbnail ? 1 : pcd_res, 0,0,0, pcd_get_rot(&h->img, 0), &h->left, &h->top, &h->width, &h->height)) goto oops; if (-1 == pcd_decode(&h->img)) goto oops; i->width = h->width; i->height = h->height; i->npages = 1; return h; oops: free(h); return NULL; } static void pcd_read(unsigned char *dst, unsigned int line, void *data) { struct pcd_state *h = data; pcd_get_image_line(&h->img, line, dst, PCD_TYPE_RGB, 0); } static void pcd_done(void *data) { struct pcd_state *h = data; pcd_close(&h->img); free(h); } static struct ida_loader pcd_loader = { magic: "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff", moff: 0, mlen: 16, name: "libpcd", init: pcd_init, read: pcd_read, done: pcd_done, }; static void __init init_rd(void) { load_register(&pcd_loader); } fbi-2.10/rd/read-xwd.c0000644000175000017500000002225112506525033012613 0ustar jmmjmm#include #include #include #include #include #include #include #ifdef HAVE_ENDIAN_H # include #endif #include "readers.h" #include "viewer.h" #include "xwd.h" #include "x11.h" #include "ida.h" /* xwd files are big endian */ #if BYTE_ORDER == BIG_ENDIAN # define be16_to_cpu(x) (x) # define be32_to_cpu(x) (x) #elif BYTE_ORDER == LITTLE_ENDIAN # define be16_to_cpu(x) ((((uint16_t)x>>8) & 0x00ff) |\ (((uint16_t)x<<8) & 0xff00)) # define be32_to_cpu(x) ((((uint32_t)x>>24) & 0x000000ff) |\ (((uint32_t)x>>8) & 0x0000ff00) |\ (((uint32_t)x<<8) & 0x00ff0000) |\ (((uint32_t)x<<24) & 0xff000000)) #else # error "Oops: unknown byte order" #endif static char *vclass[] = { "StaticGray", "GrayScale", "StaticColor", "PseudoColor", "TrueColor", "DirectColor", }; static char *order[] = { "LSBFirst", "MSBFirst", }; static char *fmt[] = { "XYBitmap", "XYPixmap", "ZPixmap", }; /* ----------------------------------------------------------------------- */ struct xwd_state { FILE *infile; XWDFileHeader header; XWDColor cmap[256]; int width,bpp; unsigned char *row; unsigned long *pix; unsigned long r_mask,g_mask,b_mask; int r_shift,g_shift,b_shift; int r_bits,g_bits,b_bits; }; static void xwd_map(struct xwd_state *h) { int i; unsigned long mask; h->r_mask = be32_to_cpu(h->header.red_mask); h->g_mask = be32_to_cpu(h->header.green_mask); h->b_mask = be32_to_cpu(h->header.blue_mask); for (i = 0; i < 32; i++) { mask = (1 << i); if (h->r_mask & mask) h->r_bits++; else if (!h->r_bits) h->r_shift++; if (h->g_mask & mask) h->g_bits++; else if (!h->g_bits) h->g_shift++; if (h->b_mask & mask) h->b_bits++; else if (!h->b_bits) h->b_shift++; } h->r_shift -= (8 - h->r_bits); h->g_shift -= (8 - h->g_bits); h->b_shift -= (8 - h->b_bits); #if 0 fprintf(stderr,"xwd: color: bits shift\n"); fprintf(stderr,"xwd: red : %04i %05i\n", h->r_bits, h->r_shift); fprintf(stderr,"xwd: green: %04i %05i\n", h->g_bits, h->g_shift); fprintf(stderr,"xwd: blue : %04i %05i\n", h->b_bits, h->b_shift); #endif } static void* xwd_init(FILE *fp, char *filename, unsigned int page, struct ida_image_info *i, int thumbnail) { struct xwd_state *h; char *buf; int size; h = malloc(sizeof(*h)); memset(h,0,sizeof(*h)); h->infile = fp; fread(&h->header,sizeof(h->header),1,fp); if ((be32_to_cpu(h->header.pixmap_format) >sizeof(fmt)/sizeof(char*)) || (be32_to_cpu(h->header.byte_order) >sizeof(order)/sizeof(char*)) || (be32_to_cpu(h->header.visual_class) >sizeof(vclass)/sizeof(char*))) { fprintf(stderr,"xwd: invalid file\n"); goto oops; } if (debug) fprintf(stderr, "xwd: fmt=%s depth=%" PRId32 " size=%" PRId32 "x%" PRId32 " bpp=%" PRId32 " bpl=%" PRId32 "\n" "xwd: order=%s vclass=%s masks=%" PRIx32 "/%" PRIx32 "/%" PRIx32 " cmap=%" PRId32 "\n", fmt[be32_to_cpu(h->header.pixmap_format)], be32_to_cpu(h->header.pixmap_depth), be32_to_cpu(h->header.pixmap_width), be32_to_cpu(h->header.pixmap_height), be32_to_cpu(h->header.bits_per_pixel), be32_to_cpu(h->header.bytes_per_line), order[be32_to_cpu(h->header.byte_order)], vclass[be32_to_cpu(h->header.visual_class)], be32_to_cpu(h->header.red_mask), be32_to_cpu(h->header.green_mask), be32_to_cpu(h->header.blue_mask), be32_to_cpu(h->header.colormap_entries)); size = be32_to_cpu(h->header.header_size)-sizeof(h->header); buf = malloc(size); fread(buf,size,1,fp); if (debug) fprintf(stderr,"xwd: name=%s\n",buf); free(buf); /* check format */ if (8 != be32_to_cpu(h->header.bits_per_pixel) && 16 != be32_to_cpu(h->header.bits_per_pixel) && 24 != be32_to_cpu(h->header.bits_per_pixel) && 32 != be32_to_cpu(h->header.bits_per_pixel)) { fprintf(stderr,"xwd: Oops: bpp != 8/16/24/32\n"); goto oops; } if (be32_to_cpu(h->header.pixmap_format) != ZPixmap) { fprintf(stderr,"xwd: Oops: can read only ZPixmap format\n"); goto oops; } /* color map */ if (be32_to_cpu(h->header.colormap_entries) > 256) { fprintf(stderr,"xwd: colormap too big (%" PRId32 " > 256)\n", be32_to_cpu(h->header.colormap_entries)); goto oops; } fread(&h->cmap,sizeof(XWDColor),be32_to_cpu(h->header.colormap_entries),fp); #if 0 for (i = 0; i < be32_to_cpu(h->header.colormap_entries); i++) fprintf(stderr, "xwd cmap: %d: " "pix=%ld rgb=%d/%d/%d flags=%d pad=%d\n",i, be32_to_cpu(h->cmap[i].pixel), be16_to_cpu(h->cmap[i].red), be16_to_cpu(h->cmap[i].green), be16_to_cpu(h->cmap[i].blue), h->cmap[i].flags, h->cmap[i].pad); #endif switch (be32_to_cpu(h->header.visual_class)) { case StaticGray: case PseudoColor: /* nothing */ break; case TrueColor: case DirectColor: xwd_map(h); break; default: fprintf(stderr,"xwd: Oops: visual not implemented [%s]\n", vclass[be32_to_cpu(h->header.visual_class)]); goto oops; } h->bpp = be32_to_cpu(h->header.bits_per_pixel); h->width = be32_to_cpu(h->header.pixmap_width); h->pix = malloc(h->width*sizeof(unsigned long)); h->row = malloc(be32_to_cpu(h->header.bytes_per_line)); i->width = be32_to_cpu(h->header.pixmap_width); i->height = be32_to_cpu(h->header.pixmap_height); i->npages = 1; return h; oops: fclose(h->infile); free(h); return NULL; } static void xwd_parse(unsigned char *dst, unsigned int line, void *data) { struct xwd_state *h = data; unsigned long r,g,b; int x,i,bits; /* data to 32bit values */ memset(h->pix,0,h->width * sizeof(unsigned long)); if (be32_to_cpu(h->header.byte_order) == LSBFirst) { for (i = 0, x = 0; x < h->width; x++) for (bits = 0; bits < h->bpp; bits += 8) h->pix[x] |= h->row[i++] << bits; } else { for (i = 0, x = 0; x < h->width; x++) for (bits = 0; bits < h->bpp; bits += 8) h->pix[x] <<= 8, h->pix[x] |= h->row[i++]; } /* transform to rgb */ switch (be32_to_cpu(h->header.visual_class)) { case StaticGray: for (x = 0; x < h->width; x++) { dst[0] = h->pix[x]; dst[1] = h->pix[x]; dst[2] = h->pix[x]; dst += 3; } break; case PseudoColor: for (x = 0; x < h->width; x++) { dst[0] = be16_to_cpu(h->cmap[h->pix[x]].red) >> 8; dst[1] = be16_to_cpu(h->cmap[h->pix[x]].green) >> 8; dst[2] = be16_to_cpu(h->cmap[h->pix[x]].blue) >> 8; dst += 3; } break; case TrueColor: case DirectColor: for (x = 0; x < h->width; x++) { r = h->pix[x] & h->r_mask; if (h->r_shift > 0) r >>= h->r_shift; if (h->r_shift < 0) r <<= -h->r_shift; g = h->pix[x] & h->g_mask; if (h->g_shift > 0) g >>= h->g_shift; if (h->g_shift < 0) g <<= -h->g_shift; b = h->pix[x] & h->b_mask; if (h->b_shift > 0) b >>= h->b_shift; if (h->b_shift < 0) b <<= -h->b_shift; dst[0] = r; dst[1] = g; dst[2] = b; dst += 3; } break; } } static void xwd_read(unsigned char *dst, unsigned int line, void *data) { struct xwd_state *h = data; fread(h->row,be32_to_cpu(h->header.bytes_per_line),1,h->infile); xwd_parse(dst, line, data); } static void xwd_done(void *data) { struct xwd_state *h = data; fclose(h->infile); free(h->pix); free(h->row); free(h); } static struct ida_loader xwd_loader = { magic: "\0\0\0\7", moff: 4, mlen: 4, name: "xwd", init: xwd_init, read: xwd_read, done: xwd_done, }; static void __init init_rd(void) { load_register(&xwd_loader); } /* ----------------------------------------------------------------------- */ void parse_ximage(struct ida_image *dest, XImage *src) { struct xwd_state h; Colormap cmap; XColor col; int y,i; memset(&h,0,sizeof(h)); h.width = src->width; h.bpp = src->bits_per_pixel; h.header.red_mask = be32_to_cpu(info->red_mask); h.header.green_mask = be32_to_cpu(info->green_mask); h.header.blue_mask = be32_to_cpu(info->blue_mask); h.header.visual_class = be32_to_cpu(info->class); h.header.byte_order = be32_to_cpu(ImageByteOrder(dpy)); h.pix = malloc(src->width * sizeof(unsigned long)); switch (be32_to_cpu(h.header.visual_class)) { case PseudoColor: cmap = DefaultColormapOfScreen(XtScreen(app_shell)); for (i = 0; i < 256; i++) { col.pixel = i; XQueryColor(dpy,cmap,&col); h.cmap[i].red = be16_to_cpu(col.red); h.cmap[i].green = be16_to_cpu(col.green); h.cmap[i].blue = be16_to_cpu(col.blue); } break; case TrueColor: case DirectColor: xwd_map(&h); break; } memset(dest,0,sizeof(*dest)); dest->i.width = src->width; dest->i.height = src->height; dest->data = malloc(dest->i.width * dest->i.height * 3); memset(dest->data,0,dest->i.width * dest->i.height * 3); for (y = 0; y < src->height; y++) { h.row = src->data + y*src->bytes_per_line; xwd_parse(dest->data + 3*y*dest->i.width, y, &h); } free(h.pix); } fbi-2.10/rd/magick.c0000644000175000017500000000316212506525033012333 0ustar jmmjmm#include #include #include #include #include "loader.h" #include "viewer.h" extern char *binary; static int first = 1; static ExceptionInfo exception; struct magick_state { ImageInfo *image_info; Image *image; }; static void* magick_init(FILE *fp, char *filename, int *width, int *height) { struct magick_state *h; /* libmagick wants a filename */ fclose(fp); if (first) { /* init library first time */ MagickIncarnate(binary); GetExceptionInfo(&exception); first = 0; } h = malloc(sizeof(*h)); memset(h,0,sizeof(*h)); h->image_info=CloneImageInfo(NULL); strcpy(h->image_info->filename,filename); h->image = ReadImage(h->image_info,&exception); if (NULL == h->image) { MagickError(exception.severity,exception.reason,exception.description); goto oops; } *width = h->image->rows; *height = h->image->columns; return h; oops: if (h->image) DestroyImage(h->image); if (h->image_info) DestroyImageInfo(h->image_info); free(h); return NULL; } static void magick_read(unsigned char *dst, int line, void *data) { struct magick_state *h = data; DispatchImage (h->image,0,line,h->image->columns, 1, "RGB", 0, data); } static void magick_done(void *data) { struct magick_state *h = data; DestroyImageInfo(h->image_info); DestroyImage(h->image); free(h); } static struct ida_loader magick_loader = { name: "libmagick", init: magick_init, read: magick_read, done: magick_done, }; static void __init init_rd(void) { load_register(&magick_loader); } fbi-2.10/rd/read-tiff.c0000644000175000017500000001212712506525033012742 0ustar jmmjmm#include #include #include #include #include #include #include "readers.h" struct tiff_state { TIFF* tif; char emsg[1024]; tdir_t ndirs; /* Number of directories */ /* (could be interpreted as number of pages) */ uint32 width,height; uint16 config,nsamples,depth,fillorder,photometric; uint32* row; uint32* image; uint16 resunit; float xres,yres; }; static void* tiff_init(FILE *fp, char *filename, unsigned int page, struct ida_image_info *i, int thumbnail) { struct tiff_state *h; fclose(fp); h = malloc(sizeof(*h)); memset(h,0,sizeof(*h)); TIFFSetWarningHandler(NULL); h->tif = TIFFOpen(filename,"r"); if (NULL == h->tif) goto oops; /* Determine number of directories */ h->ndirs = 1; while (TIFFReadDirectory(h->tif)) h->ndirs++; i->npages = h->ndirs; /* Select requested directory (page) */ if (!TIFFSetDirectory(h->tif, (tdir_t)page)) goto oops; TIFFGetField(h->tif, TIFFTAG_IMAGEWIDTH, &h->width); TIFFGetField(h->tif, TIFFTAG_IMAGELENGTH, &h->height); TIFFGetField(h->tif, TIFFTAG_PLANARCONFIG, &h->config); TIFFGetField(h->tif, TIFFTAG_SAMPLESPERPIXEL, &h->nsamples); TIFFGetField(h->tif, TIFFTAG_BITSPERSAMPLE, &h->depth); TIFFGetField(h->tif, TIFFTAG_FILLORDER, &h->fillorder); TIFFGetField(h->tif, TIFFTAG_PHOTOMETRIC, &h->photometric); h->row = malloc(TIFFScanlineSize(h->tif)); if (debug) fprintf(stderr,"tiff: %" PRId32 "x%" PRId32 ", planar=%d, " "nsamples=%d, depth=%d fo=%d pm=%d scanline=%" PRId32 "\n", h->width,h->height,h->config,h->nsamples,h->depth, h->fillorder,h->photometric, (uint32_t)TIFFScanlineSize(h->tif)); if (PHOTOMETRIC_PALETTE == h->photometric || PHOTOMETRIC_YCBCR == h->photometric || PHOTOMETRIC_SEPARATED == h->photometric || TIFFIsTiled(h->tif) || (1 != h->depth && 8 != h->depth)) { /* for the more difficuilt cases we let libtiff * do all the hard work. Drawback is that we lose * progressive loading and decode everything here */ if (debug) fprintf(stderr,"tiff: reading whole image [TIFFReadRGBAImage]\n"); h->image=malloc(4*h->width*h->height); TIFFReadRGBAImage(h->tif, h->width, h->height, h->image, 0); } else { if (debug) fprintf(stderr,"tiff: reading scanline by scanline\n"); h->row = malloc(TIFFScanlineSize(h->tif)); } i->width = h->width; i->height = h->height; if (TIFFGetField(h->tif, TIFFTAG_RESOLUTIONUNIT, &h->resunit) && TIFFGetField(h->tif, TIFFTAG_XRESOLUTION, &h->xres) && TIFFGetField(h->tif, TIFFTAG_YRESOLUTION, &h->yres)) { switch (h->resunit) { case RESUNIT_NONE: break; case RESUNIT_INCH: i->dpi = h->xres; break; case RESUNIT_CENTIMETER: i->dpi = res_cm_to_inch(h->xres); break; } } return h; oops: if (h->tif) TIFFClose(h->tif); free(h); return NULL; } static void tiff_read(unsigned char *dst, unsigned int line, void *data) { struct tiff_state *h = data; int s,on,off; if (h->image) { /* loaded whole image using TIFFReadRGBAImage() */ uint32 *row = h->image + h->width * (h->height - line -1); load_rgba(dst,(unsigned char*)row,h->width); return; } if (h->config == PLANARCONFIG_CONTIG) { TIFFReadScanline(h->tif, h->row, line, 0); } else if (h->config == PLANARCONFIG_SEPARATE) { for (s = 0; s < h->nsamples; s++) TIFFReadScanline(h->tif, h->row, line, s); } switch (h->nsamples) { case 1: if (1 == h->depth) { /* black/white */ on = 0, off = 0; if (PHOTOMETRIC_MINISWHITE == h->photometric) on = 0, off = 255; if (PHOTOMETRIC_MINISBLACK == h->photometric) on = 255, off = 0; #if 0 /* Huh? Does TIFFReadScanline handle this already ??? */ if (FILLORDER_MSB2LSB == h->fillorder) load_bits_msb(dst,(unsigned char*)(h->row),h->width,on,off); else load_bits_lsb(dst,(unsigned char*)(h->row),h->width,on,off); #else load_bits_msb(dst,(unsigned char*)(h->row),h->width,on,off); #endif } else { /* grayscaled */ load_gray(dst,(unsigned char*)(h->row),h->width); } break; case 3: /* rgb */ memcpy(dst,h->row,3*h->width); break; case 4: /* rgb+alpha */ load_rgba(dst,(unsigned char*)(h->row),h->width); break; } } static void tiff_done(void *data) { struct tiff_state *h = data; TIFFClose(h->tif); if (h->row) free(h->row); if (h->image) free(h->image); free(h); } static struct ida_loader tiff1_loader = { magic: "MM\x00\x2a", moff: 0, mlen: 4, name: "libtiff", init: tiff_init, read: tiff_read, done: tiff_done, }; static struct ida_loader tiff2_loader = { magic: "II\x2a\x00", moff: 0, mlen: 4, name: "libtiff", init: tiff_init, read: tiff_read, done: tiff_done, }; static void __init init_rd(void) { load_register(&tiff1_loader); load_register(&tiff2_loader); } fbi-2.10/rd/read-bmp.c0000644000175000017500000001253612506525033012574 0ustar jmmjmm#include #include #include #include #include #ifdef HAVE_ENDIAN_H # include #endif #include "readers.h" /* ---------------------------------------------------------------------- */ typedef unsigned int uint32; typedef unsigned short uint16; /* bitmap files are little endian */ #if BYTE_ORDER == LITTLE_ENDIAN # define le16_to_cpu(x) (x) # define le32_to_cpu(x) (x) #elif BYTE_ORDER == BIG_ENDIAN # define le16_to_cpu(x) (((x>>8) & 0x00ff) |\ ((x<<8) & 0xff00)) # define le32_to_cpu(x) (((x>>24) & 0x000000ff) |\ ((x>>8) & 0x0000ff00) |\ ((x<<8) & 0x00ff0000) |\ ((x<<24) & 0xff000000)) #else # error "Oops: unknown byte order" #endif /* ---------------------------------------------------------------------- */ /* load */ struct bmp_hdr { uint32 foobar; uint32 size; /* == BitMapInfoHeader */ uint32 width; uint32 height; uint16 planes; uint16 bit_cnt; char compression[4]; uint32 image_size; uint32 xpels_meter; uint32 ypels_meter; uint32 num_colors; /* used colors */ uint32 imp_colors; /* important colors */ /* may be more for some codecs */ }; struct bmp_cmap { unsigned char blue; unsigned char green; unsigned char red; unsigned char unused; }; struct bmp_state { struct bmp_hdr hdr; struct bmp_cmap cmap[256]; FILE *fp; }; static void* bmp_init(FILE *fp, char *filename, unsigned int page, struct ida_image_info *i, int thumbnail) { struct bmp_state *h; h = malloc(sizeof(*h)); memset(h,0,sizeof(*h)); h->fp = fp; fseek(fp,10,SEEK_SET); fread(&h->hdr,sizeof(struct bmp_hdr),1,fp); #if BYTE_ORDER == BIG_ENDIAN h->hdr.foobar = le32_to_cpu(h->hdr.foobar); h->hdr.size = le32_to_cpu(h->hdr.size); h->hdr.width = le32_to_cpu(h->hdr.width); h->hdr.height = le32_to_cpu(h->hdr.height); h->hdr.planes = le16_to_cpu(h->hdr.planes); h->hdr.bit_cnt = le16_to_cpu(h->hdr.bit_cnt); h->hdr.image_size = le32_to_cpu(h->hdr.image_size); h->hdr.xpels_meter = le32_to_cpu(h->hdr.xpels_meter); h->hdr.ypels_meter = le32_to_cpu(h->hdr.ypels_meter); h->hdr.num_colors = le32_to_cpu(h->hdr.num_colors); h->hdr.imp_colors = le32_to_cpu(h->hdr.imp_colors); #endif if (debug) fprintf(stderr,"bmp: hdr=%d size=%dx%d planes=%d" " bits=%d size=%d res=%dx%d colors=%d/%d | %d\n", h->hdr.size,h->hdr.width,h->hdr.height, h->hdr.planes,h->hdr.bit_cnt,h->hdr.image_size, h->hdr.xpels_meter,h->hdr.ypels_meter, h->hdr.num_colors,h->hdr.imp_colors,h->hdr.foobar); if (h->hdr.bit_cnt != 1 && h->hdr.bit_cnt != 4 && h->hdr.bit_cnt != 8 && h->hdr.bit_cnt != 24) { fprintf(stderr,"bmp: can't handle depth [%d]\n",h->hdr.bit_cnt); goto oops; } if (h->hdr.compression[0] || h->hdr.compression[1] || h->hdr.compression[2] || h->hdr.compression[3]) { fprintf(stderr,"bmp: can't handle compressed bitmaps [%c%c%c%c]\n", h->hdr.compression[0], h->hdr.compression[1], h->hdr.compression[2], h->hdr.compression[3]); goto oops; } if (0 == h->hdr.num_colors && h->hdr.bit_cnt <= 8) h->hdr.num_colors = (1 << h->hdr.bit_cnt); if (h->hdr.num_colors > 256) h->hdr.num_colors = 256; if (h->hdr.num_colors) { fseek(fp,14+h->hdr.size,SEEK_SET); fread(&h->cmap,sizeof(struct bmp_cmap),h->hdr.num_colors,fp); } i->width = h->hdr.width; i->height = h->hdr.height; if (h->hdr.xpels_meter) i->dpi = res_m_to_inch(h->hdr.xpels_meter); i->npages = 1; return h; oops: free(h); return NULL; } static void bmp_read(unsigned char *dst, unsigned int line, void *data) { struct bmp_state *h = data; unsigned int ll,y,x,pixel,byte = 0; ll = (((h->hdr.width * h->hdr.bit_cnt + 31) & ~0x1f) >> 3); y = h->hdr.height - line - 1; fseek(h->fp,h->hdr.foobar + y * ll,SEEK_SET); switch (h->hdr.bit_cnt) { case 1: for (x = 0; x < h->hdr.width; x++) { if (0 == (x & 0x07)) byte = fgetc(h->fp); pixel = byte & (0x80 >> (x & 0x07)) ? 1 : 0; *(dst++) = h->cmap[pixel].red; *(dst++) = h->cmap[pixel].green; *(dst++) = h->cmap[pixel].blue; } break; case 4: for (x = 0; x < h->hdr.width; x++) { if (x & 1) { pixel = byte & 0xf; } else { byte = fgetc(h->fp); pixel = byte >> 4; } *(dst++) = h->cmap[pixel].red; *(dst++) = h->cmap[pixel].green; *(dst++) = h->cmap[pixel].blue; } break; case 8: for (x = 0; x < h->hdr.width; x++) { pixel = fgetc(h->fp); *(dst++) = h->cmap[pixel].red; *(dst++) = h->cmap[pixel].green; *(dst++) = h->cmap[pixel].blue; } break; case 24: for (x = 0; x < h->hdr.width; x++) { dst[2] = fgetc(h->fp); dst[1] = fgetc(h->fp); dst[0] = fgetc(h->fp); dst += 3; } break; default: memset(dst,128,h->hdr.width*3); break; } } static void bmp_done(void *data) { struct bmp_state *h = data; fclose(h->fp); free(h); } static struct ida_loader bmp_loader = { magic: "BM", moff: 0, mlen: 2, name: "bmp", init: bmp_init, read: bmp_read, done: bmp_done, }; static void __init init_rd(void) { load_register(&bmp_loader); } fbi-2.10/rd/read-jpeg.c0000644000175000017500000001242512506525033012740 0ustar jmmjmm#include #include #include #include #include #include #include #include #include "readers.h" #include "misc.h" /* ---------------------------------------------------------------------- */ /* load */ struct jpeg_state { FILE * infile; /* source file */ struct jpeg_decompress_struct cinfo; struct jpeg_error_mgr jerr; jmp_buf errjump; JSAMPARRAY buffer; /* Output row buffer */ int row_stride,linelength; /* physical row width in output buffer */ unsigned char *image,*ptr; /* thumbnail */ unsigned char *thumbnail; unsigned int tpos, tsize; }; /* ---------------------------------------------------------------------- */ /* data source manager for thumbnail images */ static void thumbnail_src_init(struct jpeg_decompress_struct *cinfo) { struct jpeg_state *h = container_of(cinfo, struct jpeg_state, cinfo); cinfo->src->next_input_byte = h->thumbnail; cinfo->src->bytes_in_buffer = h->tsize; } static int thumbnail_src_fill(struct jpeg_decompress_struct *cinfo) { fprintf(stderr,"jpeg: panic: no more thumbnail input data\n"); exit(1); } static void thumbnail_src_skip(struct jpeg_decompress_struct *cinfo, long num_bytes) { cinfo->src->next_input_byte += num_bytes; } static void thumbnail_src_term(struct jpeg_decompress_struct *cinfo) { /* nothing */ } static struct jpeg_source_mgr thumbnail_mgr = { .init_source = thumbnail_src_init, .fill_input_buffer = thumbnail_src_fill, .skip_input_data = thumbnail_src_skip, .resync_to_restart = jpeg_resync_to_restart, .term_source = thumbnail_src_term, }; /* ---------------------------------------------------------------------- */ /* jpeg loader */ static void jerror_exit(j_common_ptr info) { struct jpeg_decompress_struct *cinfo = (struct jpeg_decompress_struct *)info; struct jpeg_state *h = container_of(cinfo, struct jpeg_state, cinfo); cinfo->err->output_message(info); longjmp(h->errjump, 1); jpeg_destroy_decompress(cinfo); exit(1); } static void* jpeg_init(FILE *fp, char *filename, unsigned int page, struct ida_image_info *i, int thumbnail) { struct jpeg_state *h; jpeg_saved_marker_ptr mark; h = malloc(sizeof(*h)); memset(h,0,sizeof(*h)); h->infile = fp; h->cinfo.err = jpeg_std_error(&h->jerr); h->cinfo.err->error_exit = jerror_exit; if(setjmp(h->errjump)) return 0; jpeg_create_decompress(&h->cinfo); jpeg_save_markers(&h->cinfo, JPEG_COM, 0xffff); /* comment */ jpeg_save_markers(&h->cinfo, JPEG_APP0+1, 0xffff); /* EXIF */ jpeg_stdio_src(&h->cinfo, h->infile); jpeg_read_header(&h->cinfo, TRUE); for (mark = h->cinfo.marker_list; NULL != mark; mark = mark->next) { switch (mark->marker) { case JPEG_COM: if (debug) fprintf(stderr,"jpeg: comment found (COM marker) [%.*s]\n", (int)mark->data_length, mark->data); load_add_extra(i,EXTRA_COMMENT,mark->data,mark->data_length); break; case JPEG_APP0 +1: if (debug) fprintf(stderr,"jpeg: exif data found (APP1 marker)\n"); load_add_extra(i,EXTRA_COMMENT,mark->data,mark->data_length); if (thumbnail) { ExifData *ed; ed = exif_data_new_from_data(mark->data,mark->data_length); if (ed->data && ed->data[0] == 0xff && ed->data[1] == 0xd8) { if (debug) fprintf(stderr,"jpeg: exif thumbnail found\n"); /* save away thumbnail data */ h->thumbnail = malloc(ed->size); h->tsize = ed->size; memcpy(h->thumbnail,ed->data,ed->size); } exif_data_unref(ed); } break; } } if (h->thumbnail) { /* save image size */ i->thumbnail = 1; i->real_width = h->cinfo.image_width; i->real_height = h->cinfo.image_height; /* re-setup jpeg */ jpeg_destroy_decompress(&h->cinfo); fclose(h->infile); h->infile = NULL; jpeg_create_decompress(&h->cinfo); h->cinfo.src = &thumbnail_mgr; jpeg_read_header(&h->cinfo, TRUE); } h->cinfo.out_color_space = JCS_RGB; jpeg_start_decompress(&h->cinfo); i->width = h->cinfo.image_width; i->height = h->cinfo.image_height; i->npages = 1; switch (h->cinfo.density_unit) { case 0: /* unknown */ break; case 1: /* dot per inch */ i->dpi = h->cinfo.X_density; break; case 2: /* dot per cm */ i->dpi = res_cm_to_inch(h->cinfo.X_density); break; } return h; } static void jpeg_read(unsigned char *dst, unsigned int line, void *data) { struct jpeg_state *h = data; JSAMPROW row = dst; if(setjmp(h->errjump)) return; jpeg_read_scanlines(&h->cinfo, &row, 1); } static void jpeg_done(void *data) { struct jpeg_state *h = data; if (setjmp(h->errjump)) return; jpeg_destroy_decompress(&h->cinfo); if (h->infile) fclose(h->infile); if (h->thumbnail) free(h->thumbnail); free(h); } struct ida_loader jpeg_loader = { magic: "\xff\xd8", moff: 0, mlen: 2, name: "libjpeg", init: jpeg_init, read: jpeg_read, done: jpeg_done, }; static void __init init_rd(void) { load_register(&jpeg_loader); } fbi-2.10/rd/read-png.c0000644000175000017500000000737312506525033012605 0ustar jmmjmm#include #include #include #include #include #include #include "readers.h" static const char *ct[] = { "gray", "X1", "rgb", "palette", "graya", "X5", "rgba", "X7", }; struct png_state { FILE *infile; png_structp png; png_infop info; png_bytep image; png_uint_32 w,h; int color_type; }; static void* png_init(FILE *fp, char *filename, unsigned int page, struct ida_image_info *i, int thumbnail) { struct png_state *h; int bit_depth, interlace_type; int pass, number_passes; unsigned int y; png_uint_32 resx, resy; png_color_16 *file_bg, my_bg = { .red = 192, .green = 192, .blue = 192, .gray = 192, }; int unit; h = malloc(sizeof(*h)); memset(h,0,sizeof(*h)); h->infile = fp; h->png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (NULL == h->png) goto oops; h->info = png_create_info_struct(h->png); if (NULL == h->info) goto oops; png_init_io(h->png, h->infile); png_read_info(h->png, h->info); png_get_IHDR(h->png, h->info, &h->w, &h->h, &bit_depth,&h->color_type,&interlace_type, NULL,NULL); png_get_pHYs(h->png, h->info, &resx, &resy, &unit); i->width = h->w; i->height = h->h; if (PNG_RESOLUTION_METER == unit) i->dpi = res_m_to_inch(resx); if (debug) fprintf(stderr,"png: color_type=%s #1\n",ct[h->color_type]); i->npages = 1; png_set_packing(h->png); if (bit_depth == 16) png_set_strip_16(h->png); if (h->color_type == PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb(h->png); if (h->color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) png_set_expand_gray_1_2_4_to_8(h->png); if (png_get_bKGD(h->png, h->info, &file_bg)) { png_set_background(h->png,file_bg,PNG_BACKGROUND_GAMMA_FILE,1,1.0); } else { png_set_background(h->png,&my_bg,PNG_BACKGROUND_GAMMA_SCREEN,0,1.0); } number_passes = png_set_interlace_handling(h->png); png_read_update_info(h->png, h->info); h->color_type = png_get_color_type(h->png, h->info); if (debug) fprintf(stderr,"png: color_type=%s #2\n",ct[h->color_type]); h->image = malloc(i->width * i->height * 4); for (pass = 0; pass < number_passes-1; pass++) { if (debug) fprintf(stderr,"png: pass #%d\n",pass); for (y = 0; y < i->height; y++) { png_bytep row = h->image + y * i->width * 4; png_read_rows(h->png, &row, NULL, 1); } } return h; oops: if (h->image) free(h->image); if (h->png) png_destroy_read_struct(&h->png, NULL, NULL); fclose(h->infile); free(h); return NULL; } static void png_read(unsigned char *dst, unsigned int line, void *data) { struct png_state *h = data; png_bytep row = h->image + line * h->w * 4; switch (h->color_type) { case PNG_COLOR_TYPE_GRAY: png_read_rows(h->png, &row, NULL, 1); load_gray(dst,row,h->w); break; case PNG_COLOR_TYPE_RGB: png_read_rows(h->png, &row, NULL, 1); memcpy(dst,row,3*h->w); break; case PNG_COLOR_TYPE_RGB_ALPHA: png_read_rows(h->png, &row, NULL, 1); load_rgba(dst,row,h->w); break; case PNG_COLOR_TYPE_GRAY_ALPHA: png_read_rows(h->png, &row, NULL, 1); load_graya(dst,row,h->w); break; default: /* shouldn't happen */ fprintf(stderr,"Oops: %s:%d\n",__FILE__,__LINE__); exit(1); } } static void png_done(void *data) { struct png_state *h = data; free(h->image); png_destroy_read_struct(&h->png, &h->info, NULL); fclose(h->infile); free(h); } static struct ida_loader png_loader = { magic: "\x89PNG", moff: 0, mlen: 4, name: "libpng", init: png_init, read: png_read, done: png_done, }; static void __init init_rd(void) { load_register(&png_loader); } fbi-2.10/filter.h0000644000175000017500000000064512506525033011770 0ustar jmmjmm struct op_3x3_parm { int f1[3]; int f2[3]; int f3[3]; int mul,div,add; }; struct op_sharpe_parm { int factor; }; struct op_resize_parm { int width; int height; int dpi; }; struct op_rotate_parm { int angle; }; extern struct ida_op desc_grayscale; extern struct ida_op desc_3x3; extern struct ida_op desc_sharpe; extern struct ida_op desc_resize; extern struct ida_op desc_rotate; fbi-2.10/genthumbnail.h0000644000175000017500000000010412506525033013146 0ustar jmmjmmint create_thumbnail(char *filename, unsigned char *dest, int max); fbi-2.10/selections.c0000644000175000017500000004102512506525033012643 0ustar jmmjmm#include #include #include #include #include #include #include #include #include #include #include #include "ida.h" #include "readers.h" #include "writers.h" #include "viewer.h" #include "xwd.h" #include "xdnd.h" #include "selections.h" #include "list.h" Atom XA_TARGETS, XA_DONE; Atom XA_FILE_NAME, XA_FILE; Atom XA_BACKGROUND, XA_FOREGROUND, XA_PIXEL; Atom _MOTIF_EXPORT_TARGETS; Atom _MOTIF_CLIPBOARD_TARGETS; Atom _MOTIF_DEFERRED_CLIPBOARD_TARGETS; Atom _MOTIF_SNAPSHOT; Atom _MOTIF_DROP; Atom _MOTIF_LOSE_SELECTION; Atom _NETSCAPE_URL; Atom MIME_TEXT_URI_LIST; Atom MIME_IMAGE_PPM; Atom MIME_IMAGE_PGM; Atom MIME_IMAGE_XPM; Atom MIME_IMAGE_BMP; Atom MIME_IMAGE_JPEG; Atom MIME_IMAGE_GIF; Atom MIME_IMAGE_PNG; Atom MIME_IMAGE_TIFF; /* ---------------------------------------------------------------------- */ /* send data (drags, copy) */ struct sel_data { struct list_head list; Atom atom; struct ida_image img; Pixmap pixmap; char *filename; Pixmap icon_pixmap; Widget icon_widget; }; static struct list_head selections; static void iconify(Widget widget, struct sel_data *data) { struct ida_image small; unsigned int scale,x,y,depth; char *src,*dst; Arg args[4]; Cardinal n=0; /* calc size */ memset(&small,0,sizeof(small)); for (scale = 1;; scale++) { small.i.width = data->img.i.width / scale; small.i.height = data->img.i.height / scale; if (small.i.width < 128 && small.i.height < 128) break; } /* scale down & create pixmap */ dst = small.data = malloc(small.i.width * small.i.height * 3); for (y = 0; y < small.i.height; y++) { src = data->img.data + 3 * y * scale * data->img.i.width; for (x = 0; x < small.i.width; x++) { dst[0] = src[0]; dst[1] = src[1]; dst[2] = src[2]; dst += 3; src += 3*scale; } } data->icon_pixmap = image_to_pixmap(&small); /* build DnD icon */ n = 0; depth = DefaultDepthOfScreen(XtScreen(widget)); XtSetArg(args[n], XmNpixmap, data->icon_pixmap); n++; XtSetArg(args[n], XmNwidth, small.i.width); n++; XtSetArg(args[n], XmNheight, small.i.height); n++; XtSetArg(args[n], XmNdepth, depth); n++; data->icon_widget = XmCreateDragIcon(widget,"dragicon",args,n); free(small.data); } static struct sel_data* sel_find(Atom selection) { struct list_head *item; struct sel_data *sel; list_for_each(item,&selections) { sel = list_entry(item, struct sel_data, list); if (sel->atom == selection) return sel; } return NULL; } static void sel_free(Atom selection) { struct sel_data *sel; sel = sel_find(selection); if (NULL == sel) return; if (sel->filename) { unlink(sel->filename); free(sel->filename); } if (sel->icon_widget) XtDestroyWidget(sel->icon_widget); if (sel->icon_pixmap) XFreePixmap(dpy,sel->icon_pixmap); if (sel->pixmap) XFreePixmap(dpy,sel->pixmap); if (sel->img.data) free(sel->img.data); list_del(&sel->list); free(sel); } static struct sel_data* sel_init(Atom selection) { struct sel_data *sel; sel_free(selection); sel = malloc(sizeof(*sel)); memset(sel,0,sizeof(*sel)); sel->atom = selection; sel->img = ida->img; sel->img.data = malloc(ida->img.i.width * ida->img.i.height * 3); memcpy(sel->img.data, ida->img.data, ida->img.i.width * ida->img.i.height * 3); list_add_tail(&sel->list,&selections); return sel; } static void sel_tmpfile(struct sel_data *sel, struct ida_writer *wr) { static char *base = "ida"; char *tmpdir; FILE *fp; int fd; tmpdir = getenv("TMPDIR"); if (NULL == tmpdir) tmpdir="/tmp"; sel->filename = malloc(strlen(tmpdir)+strlen(base)+16); sprintf(sel->filename,"%s/%s-XXXXXX",tmpdir,base); fd = mkstemp(sel->filename); fp = fdopen(fd,"w"); wr->write(fp,&sel->img); fclose(fp); } Atom sel_unique_atom(Widget widget) { char id_name[32]; Atom id; int i; for (i = 0;; i++) { sprintf(id_name,"_IDA_DATA_%lX_%d",XtWindow(widget),i); id = XInternAtom(XtDisplay(widget),id_name,False); if (NULL == sel_find(id)) break; } return id; } void selection_convert(Widget widget, XtPointer ignore, XtPointer call_data) { XmConvertCallbackStruct *ccs = call_data; unsigned long *ldata; unsigned char *cdata; struct sel_data *sel; char *filename; int n; if (debug) { char *t = !ccs->target ? NULL : XGetAtomName(dpy,ccs->target); char *s = !ccs->selection ? NULL : XGetAtomName(dpy,ccs->selection); fprintf(stderr,"conv: target=%s selection=%s\n",t,s); if (t) XFree(t); if (s) XFree(s); } /* tell which formats we can handle */ if ((ccs->target == XA_TARGETS) || (ccs->target == _MOTIF_CLIPBOARD_TARGETS) || (ccs->target == _MOTIF_DEFERRED_CLIPBOARD_TARGETS) || (ccs->target == _MOTIF_EXPORT_TARGETS)) { n = 0; ldata = (Atom*)XtMalloc(sizeof(Atom)*12); if (ccs->target != _MOTIF_CLIPBOARD_TARGETS) { ldata[n++] = XA_TARGETS; ldata[n++] = MIME_IMAGE_PPM; ldata[n++] = XA_PIXMAP; ldata[n++] = XA_FOREGROUND; ldata[n++] = XA_BACKGROUND; ldata[n++] = XA_COLORMAP; ldata[n++] = XA_FILE_NAME; ldata[n++] = XA_FILE; ldata[n++] = MIME_TEXT_URI_LIST; ldata[n++] = _NETSCAPE_URL; } ccs->value = ldata; ccs->length = n; ccs->type = XA_ATOM; ccs->format = 32; ccs->status = XmCONVERT_DONE; return; } else if (ccs->target == _MOTIF_SNAPSHOT) { /* save away clipboard data */ n = 0; ldata = (Atom*)XtMalloc(sizeof(Atom)); ldata[n++] = sel_unique_atom(widget); sel_init(ldata[0]); ccs->value = ldata; ccs->length = n; ccs->type = XA_ATOM; ccs->format = 32; ccs->status = XmCONVERT_DONE; return; } sel = sel_find(ccs->selection); if (NULL == sel) { /* should not happen */ fprintf(stderr,"Oops: selection not found\n"); ccs->status = XmCONVERT_REFUSE; return; } if ((ccs->target == _MOTIF_LOSE_SELECTION) || (ccs->target == XA_DONE)) { /* free stuff */ sel_free(ccs->selection); ccs->value = NULL; ccs->length = 0; ccs->type = XA_INTEGER; ccs->format = 32; ccs->status = XmCONVERT_DONE; return; } /* convert data */ if (ccs->target == XA_BACKGROUND || ccs->target == XA_FOREGROUND || ccs->target == XA_COLORMAP) { n = 0; ldata = (Atom*)XtMalloc(sizeof(Atom)*8); if (ccs->target == XA_BACKGROUND) { ldata[n++] = WhitePixelOfScreen(XtScreen(widget)); ccs->type = XA_PIXEL; } if (ccs->target == XA_FOREGROUND) { ldata[n++] = BlackPixelOfScreen(XtScreen(widget)); ccs->type = XA_PIXEL; } if (ccs->target == XA_COLORMAP) { ldata[n++] = DefaultColormapOfScreen(XtScreen(widget)); ccs->type = XA_COLORMAP; } ccs->value = ldata; ccs->length = n; ccs->format = 32; ccs->status = XmCONVERT_DONE; } else if (ccs->target == XA_PIXMAP) { /* xfer pixmap id */ if (!sel->pixmap) sel->pixmap = image_to_pixmap(&sel->img); ldata = (Pixmap*)XtMalloc(sizeof(Pixmap)); ldata[0] = sel->pixmap; if (debug) fprintf(stderr,"conv: pixmap id is 0x%lx\n",ldata[0]); ccs->value = ldata; ccs->length = 1; ccs->type = XA_DRAWABLE; ccs->format = 32; ccs->status = XmCONVERT_DONE; } else if (ccs->target == MIME_IMAGE_PPM) { /* xfer image data directly */ cdata = XtMalloc(sel->img.i.width * sel->img.i.height * 3 + 32); n = sprintf(cdata,"P6\n%u %u\n255\n", sel->img.i.width, sel->img.i.height); memcpy(cdata+n, sel->img.data, sel->img.i.width*sel->img.i.height*3); ccs->value = cdata; ccs->length = n + sel->img.i.width * sel->img.i.height * 3; ccs->type = MIME_IMAGE_PPM; ccs->format = 8; ccs->status = XmCONVERT_DONE; } else if (ccs->target == XA_FILE_NAME || ccs->target == XA_FILE || ccs->target == XA_STRING || ccs->target == MIME_TEXT_URI_LIST || ccs->target == _NETSCAPE_URL) { /* xfer image via tmp file */ if (NULL == sel->filename) sel_tmpfile(sel,&jpeg_writer); if (ccs->target == MIME_TEXT_URI_LIST || ccs->target == _NETSCAPE_URL) { /* filename => url */ filename = XtMalloc(strlen(sel->filename)+8); sprintf(filename,"file:%s\r\n",sel->filename); ccs->type = ccs->target; if (debug) fprintf(stderr,"conv: tmp url is %s\n",filename); } else { filename = XtMalloc(strlen(sel->filename)); strcpy(filename,sel->filename); ccs->type = XA_STRING; if (debug) fprintf(stderr,"conv: tmp file is %s\n",filename); } ccs->value = filename; ccs->length = strlen(filename); ccs->format = 8; ccs->status = XmCONVERT_DONE; } else { /* shouldn't happen */ fprintf(stderr,"Huh? unknown target\n"); ccs->status = XmCONVERT_REFUSE; } } static void dnd_done(Widget widget, XtPointer ignore, XtPointer call_data) { if (debug) fprintf(stderr,"conv: transfer finished\n"); sel_free(_MOTIF_DROP); } /* ---------------------------------------------------------------------- */ /* receive data (drops, paste) */ static Atom targets[16]; static Cardinal ntargets; static void selection_xfer(Widget widget, XtPointer ignore, XtPointer call_data) { XmSelectionCallbackStruct *scs = call_data; unsigned char *cdata = scs->value; unsigned long *ldata = scs->value; Atom target = 0; unsigned int i,j,pending; char *file,*tmp; if (debug) { char *y = !scs->type ? NULL : XGetAtomName(dpy,scs->type); char *t = !scs->target ? NULL : XGetAtomName(dpy,scs->target); char *s = !scs->selection ? NULL : XGetAtomName(dpy,scs->selection); fprintf(stderr,"xfer: id=%p target=%s type=%s selection=%s\n", scs->transfer_id,t,y,s); if (y) XFree(y); if (t) XFree(t); if (s) XFree(s); } pending = scs->remaining; if (scs->target == XA_TARGETS) { /* look if we find a target we can deal with ... */ for (i = 0; !target && i < scs->length; i++) { for (j = 0; j < ntargets; j++) { if (ldata[i] == targets[j]) { target = ldata[i]; break; } } } if (target) { XmTransferValue(scs->transfer_id, target, selection_xfer, NULL, XtLastTimestampProcessed(dpy)); pending++; } if (debug) { fprintf(stderr,"xfer: available targets: "); for (i = 0; i < scs->length; i++) { char *name = !ldata[i] ? NULL : XGetAtomName(dpy,ldata[i]); fprintf(stderr,"%s%s", i != 0 ? ", " : "", name); XFree(name); } fprintf(stderr,"\n"); if (0 == scs->length) fprintf(stderr,"xfer: Huh? no TARGETS available?\n"); } } if (scs->target == XA_FILE_NAME || scs->target == XA_FILE) { /* load file */ if (debug) fprintf(stderr,"xfer: => \"%s\"\n",cdata); new_file(cdata,1); } if (scs->target == _NETSCAPE_URL) { /* load file */ if (NULL != (tmp = strchr(cdata,'\n'))) *tmp = 0; if (NULL != (tmp = strchr(cdata,'\r'))) *tmp = 0; if (debug) fprintf(stderr,"xfer: => \"%s\"\n",cdata); new_file(cdata,1); } if (scs->target == MIME_TEXT_URI_LIST) { /* load file(s) */ for (file = strtok(cdata,"\r\n"); NULL != file; file = strtok(NULL,"\r\n")) { if (debug) fprintf(stderr,"xfer: => \"%s\"\n",file); new_file(file,1); } } if (scs->target == XA_STRING) { /* might be a file name too, but don't complain if not */ if (debug) fprintf(stderr,"xfer: => \"%s\"\n",cdata); new_file(cdata,0); } if (scs->target == MIME_IMAGE_PPM || scs->target == MIME_IMAGE_PGM || scs->target == MIME_IMAGE_JPEG || scs->target == MIME_IMAGE_GIF || scs->target == MIME_IMAGE_PNG || scs->target == MIME_IMAGE_TIFF || scs->target == MIME_IMAGE_XPM || scs->target == MIME_IMAGE_BMP) { /* xfer image data directly */ char *filename = load_tmpfile("ida"); int fd; fd = mkstemp(filename); write(fd,scs->value,scs->length); close(fd); if (0 == viewer_loadimage(ida,filename,0)) { ida->file = "selection"; resize_shell(); } unlink(filename); free(filename); } if (scs->target == XA_PIXMAP) { /* beaming pixmaps between apps */ Window root; Pixmap pix; int x,y,w,h,bw,depth; XImage *ximage; struct ida_image img; pix = ldata[0]; if (debug) fprintf(stderr,"xfer: => id=0x%lx\n",pix); XGetGeometry(dpy,pix,&root,&x,&y,&w,&h,&bw,&depth); ximage = XGetImage(dpy,pix,0,0,w,h,-1,ZPixmap); parse_ximage(&img, ximage); XDestroyImage(ximage); viewer_setimage(ida,&img,"selection"); resize_shell(); } XFree(scs->value); if (1 == pending) { /* all done -- clean up */ if (debug) fprintf(stderr,"xfer: all done\n"); XmTransferDone(scs->transfer_id, XmTRANSFER_DONE_SUCCEED); XdndDropFinished(widget,scs); } } void selection_dest(Widget w, XtPointer ignore, XtPointer call_data) { XmDestinationCallbackStruct *dcs = call_data; if (NULL != sel_find(_MOTIF_DROP)) { if (debug) fprintf(stderr,"dest: ignore self drop\n"); XmTransferDone(dcs->transfer_id, XmTRANSFER_DONE_FAIL); return; } if (debug) fprintf(stderr,"dest: xfer id=%p\n",dcs->transfer_id); XmTransferValue(dcs->transfer_id, XA_TARGETS, selection_xfer, NULL, XtLastTimestampProcessed(dpy)); } /* ---------------------------------------------------------------------- */ void ipc_ac(Widget widget, XEvent *event, String *argv, Cardinal *argc) { struct sel_data *sel; Widget drag; Arg args[4]; Cardinal n=0; if (0 == *argc) return; if (debug) fprintf(stderr,"ipc: %s\n",argv[0]); if (0 == strcmp(argv[0],"paste")) { XmeClipboardSink(ida->widget,XmCOPY,NULL); } else if (0 == strcmp(argv[0],"copy")) { XmeClipboardSource(ida->widget,XmCOPY,XtLastTimestampProcessed(dpy)); } else if (0 == strcmp(argv[0],"drag")) { sel = sel_init(_MOTIF_DROP); iconify(widget,sel); XtSetArg(args[n], XmNdragOperations, XmDROP_COPY); n++; XtSetArg(args[n], XmNsourcePixmapIcon, sel->icon_widget); n++; drag = XmeDragSource(ida->widget, NULL, event, args, n); XtAddCallback(drag, XmNdragDropFinishCallback, dnd_done, NULL); } } void dnd_add(Widget widget) { Arg args[4]; Cardinal n=0; XtSetArg(args[n], XmNimportTargets, targets); n++; XtSetArg(args[n], XmNnumImportTargets, ntargets); n++; XmeDropSink(widget,args,n); XdndDropSink(widget); } void ipc_init() { _MOTIF_EXPORT_TARGETS = XInternAtom(dpy, "_MOTIF_EXPORT_TARGETS", False); _MOTIF_CLIPBOARD_TARGETS = XInternAtom(dpy, "_MOTIF_CLIPBOARD_TARGETS", False); _MOTIF_DEFERRED_CLIPBOARD_TARGETS = XInternAtom(dpy, "_MOTIF_DEFERRED_CLIPBOARD_TARGETS", False); _MOTIF_SNAPSHOT = XInternAtom(dpy, "_MOTIF_SNAPSHOT", False); _MOTIF_DROP = XInternAtom(dpy, "_MOTIF_DROP", False); _MOTIF_LOSE_SELECTION = XInternAtom(dpy, "_MOTIF_LOSE_SELECTION", False); XA_TARGETS = XInternAtom(dpy, "TARGETS", False); XA_DONE = XInternAtom(dpy, "DONE", False); XA_FILE_NAME = XInternAtom(dpy, "FILE_NAME", False); XA_FILE = XInternAtom(dpy, "FILE", False); XA_FOREGROUND = XInternAtom(dpy, "FOREGROUND", False); XA_BACKGROUND = XInternAtom(dpy, "BACKGROUND", False); XA_PIXEL = XInternAtom(dpy, "PIXEL", False); _NETSCAPE_URL = XInternAtom(dpy, "_NETSCAPE_URL", False); MIME_TEXT_URI_LIST = XInternAtom(dpy, "text/uri-list", False); MIME_IMAGE_PPM = XInternAtom(dpy, "image/ppm", False); MIME_IMAGE_PGM = XInternAtom(dpy, "image/pgm", False); MIME_IMAGE_XPM = XInternAtom(dpy, "image/xpm", False); MIME_IMAGE_BMP = XInternAtom(dpy, "image/bmp", False); MIME_IMAGE_JPEG = XInternAtom(dpy, "image/jpeg", False); MIME_IMAGE_GIF = XInternAtom(dpy, "image/gif", False); MIME_IMAGE_PNG = XInternAtom(dpy, "image/png", False); MIME_IMAGE_TIFF = XInternAtom(dpy, "image/tiff", False); targets[ntargets++] = XA_FILE_NAME; targets[ntargets++] = XA_FILE; targets[ntargets++] = _NETSCAPE_URL; targets[ntargets++] = MIME_TEXT_URI_LIST; targets[ntargets++] = MIME_IMAGE_PPM; targets[ntargets++] = MIME_IMAGE_PGM; targets[ntargets++] = MIME_IMAGE_XPM; targets[ntargets++] = MIME_IMAGE_BMP; targets[ntargets++] = MIME_IMAGE_JPEG; #ifdef HAVE_LIBGIF targets[ntargets++] = MIME_IMAGE_GIF; #endif #ifdef HAVE_LIBPNG targets[ntargets++] = MIME_IMAGE_PNG; #endif #ifdef HAVE_LIBTIFF targets[ntargets++] = MIME_IMAGE_TIFF; #endif targets[ntargets++] = XA_PIXMAP; targets[ntargets++] = XA_STRING; INIT_LIST_HEAD(&selections); } fbi-2.10/RegEditI.h0000644000175000017500000002225512506525033012140 0ustar jmmjmm/* * Motif * * Copyright (c) 1987-2012, The Open Group. All rights reserved. * * These libraries and programs are free software; you can * redistribute them and/or modify them under the terms of the GNU * Lesser General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * These libraries and programs are distributed in the hope that * they will be useful, but WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public * License along with these librararies and programs; if not, write * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth * Floor, Boston, MA 02110-1301 USA * */ /* * HISTORY */ /* $XConsortium: RegEditI.h /main/4 1995/07/14 10:05:01 drk $ */ /* Copyright (c) 1989 X Consortium 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 X CONSORTIUM 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. Except as contained in this notice, the name of the X Consortium shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from the X Consortium. */ /* * Author: Chris D. Peterson, MIT X Consortium */ /************************************************************ The Editres Protocol The Client message sent to the application is: ATOM = "ResEditor" --- RES_EDITOR_NAME FORMAT = 32 --- RES_EDIT_SEND_EVENT_FORMAT l[0] = timestamp l[1] = command atom name l[2] = ident of command. l[3] = protocol version number to use. The binary protocol has the following format: Card8: 8-bit unsingned integer Card16: 16-bit unsingned integer Card32: 32-bit unsingned integer Int16: 16-bit signed integer Window: 32-bit value Widget: 32-bit value String8: ListOfCard8 [a][b][c] represent an exclusive list of choices. All widgets are passed as a list of widgets, containing the full instance heirarch of this widget. The hierarchy is ordered from parent to child. Thus the first element of each list is the root of the widget tree (this makes verifying that the widget still exists, MUCH faster). ListOfFoo comprises a list of things in the following format: number: Card16 things: ???? This is a synchronous protocol, every request MUST be followed by a reply. Request: Serial Number: Card8 Op Code: Card8 - { SendWidgetTree = 0, SetValues = 1, GetResources = 2, GetGeometry = 3, FindChild = 4, GetValues = 5 } Length: Card32 Data: Reply: Serial Number: Card8 Type: Card8 - { Formatted = 0, Unformatted = 1, ProtocolMismatch = 2 } Length: Card32 Byte Order: All Fields are MSB -> LSB Data: Formatted: The data contains the reply information for the request as specified below if the reply type is "Formatted". The return values for the other reply types are shown below. Unformatted: Message: String8 ProtocolMismatch: RequestedVersion: Card8 ------------------------------------------------------------ SendWidgetTree: ---> Number of Entries: Card16 Entry: widget: ListOfWidgets name: String8 class: String8 window: Card32 toolkit: String8 Send Widget Tree returns the toolkit type, and a fuly specified list of widgets for each widget in the tree. This is enough information to completely reconstruct the entire widget heirarchy. The window return value contains the Xid of the window currently used by this widget. If the widget is unrealized then 0 is returned, and if widget is a non-windowed object a value of 2 is returned. SetValues: name: String8 type: String8 value: String8 Number of Entries: Card16 Entry: widget: ListOfWidgets ---> Number of Entries: Card16 Entry: widget: ListOfWidgets message: String8 SetValues will allow the same resource to be set on a number of widgets. This function will return an error message if the SetValues request caused an Xt error. GetValues: names: ListOfString8 widget: Widget ---> novalues: ListOfCard16 values: ListOfString8 GetValues will allow a number of resource values to be read on a particular widget. The request specifies the names of the resources wanted and the widget id these resources are from. The reply returns a list of indices from the requests name list of resources for which a value can not be returned. It also returns a list of returned values, in the order of the requests names list, skipping those indices present in novalues. GetResources: Number of Entries: Card16 Entry widget: ListOfWidgets: ----> Number of Entries: Card16 Entry Widget: ListOfWidgets: Error: Bool [ Message: String 8 ] [ Number of Resources: Card16 Resource: Kind: {normal, constraint} Name: String8 Class: String8 Type: String8 ] GetResource retrieves the kind, name, class and type for every widget passed to it. If an error occured with the resource fetch Error will be set to True for the given widget and a message is returned rather than the resource info. GetGeometry: Number of Entries: Card16 Entry Widget: ListOfWidgets: ----> Number of Entries: Card16 Entry Widget: ListOfWidgets: Error: Bool [ message: String 8 ] [ mapped: Boolean X: Int16 Y: Int16 Width: Card16 Height: Card16 BorderWidth: Card16 ] GetGeometry retreives the mapping state, x, y, width, height and border width for each widget specified. If an error occured with the geometry fetch "Error" will be set to True for the given widget and a message is returned rather than the geometry info. X an Y corrospond to the root coordinates of the upper left corner of the widget (outside the window border). FindChild: Widget: ListOfWidgets X: Int16 Y: Int16 ---> Widget: ListOfWidgets Find Child returns a descendent of the widget specified that is at the root coordinates specified. NOTE: The returned widget is undefined if the point is contained in two or more mapped widgets, or in two overlapping Rect objs. GetValues: names: ListOfString8 widget: Widget ---> values: ListOfString8 GetValues will allow a number of resource values to be read on a particular widget. Currently only InterViews 3.0.1 Styles and their attributes are supported. In addition, the current user interface only supports the return of 1 resource. The ability to specify and return multiple resources is defined for future editres interfaces where some or all of a widgets resource values are returned and displayed at once. ************************************************************/ #include #include #define XER_NBBY 8 /* number of bits in a byte */ #define BYTE_MASK 255 #define HEADER_SIZE 6 #define EDITRES_IS_OBJECT 2 #define EDITRES_IS_UNREALIZED 0 /* * Format for atoms. */ #define EDITRES_FORMAT 8 #define EDITRES_SEND_EVENT_FORMAT 32 /* * Atoms */ #define EDITRES_NAME "Editres" #define EDITRES_COMMAND_ATOM "EditresCommand" #define EDITRES_COMM_ATOM "EditresComm" #define EDITRES_CLIENT_VALUE "EditresClientVal" #define EDITRES_PROTOCOL_ATOM "EditresProtocol" typedef enum { SendWidgetTree = 0, SetValues = 1, GetResources = 2, GetGeometry = 3, FindChild = 4, GetValues = 5 } EditresCommand; typedef enum {NormalResource = 0, ConstraintResource = 1} ResourceType; /* * The type of a resource identifier. */ typedef unsigned char ResIdent; typedef enum {PartialSuccess= 0, Failure= 1, ProtocolMismatch= 2} EditResError; typedef struct _WidgetInfo { unsigned short num_widgets; unsigned long * ids; Widget real_widget; } WidgetInfo; typedef struct _ProtocolStream { unsigned long size, alloc; unsigned char *real_top, *top, *current; } ProtocolStream; fbi-2.10/icons.h0000644000175000017500000000022412506525033011607 0ustar jmmjmmPixmap x11_icon_fit(Display *dpy, Pixmap icon, unsigned long bg, int width, int height); void x11_icons_init(Display *dpy, unsigned long bg); fbi-2.10/xpm/0000755000175000017500000000000012506525033011131 5ustar jmmjmmfbi-2.10/xpm/zoomin.xpm0000644000175000017500000000065512506525033013200 0ustar jmmjmm/* XPM */ static char * zoomin_xpm[] = { "16 16 3 1", " c none", ". c #000000000000", "X c #868682828686", " ", " ..... ", " .XXXXX. ", " .XX . ", " .XX . . ", " .X .X .X ", " .X ..... .X ", " .X X.XXX .X ", " .X .X .X ", " . X .XX ", " . ... ", " .....X... ", " XXXXX ... ", " ..X ", " XX ", " "}; fbi-2.10/xpm/flipv.xpm0000644000175000017500000000065412506525033013004 0ustar jmmjmm/* XPM */ static char * flipv_xpm[] = { "16 16 3 1", " c none", ". c #000000000000", "X c #861782078617", " .. ", " .... ", " ...... .. ", "........ ..X ", " XX..XXXX ..X ", " ..X ..X ", " ..X ..X ", "............... ", " XX..XXXXX..XXXX", " ..X ..X ", " ..X ..X ", " ..X ........ ", " ..X ......XX", " XX ....XX ", " ..XX ", " XX "}; fbi-2.10/xpm/next.xpm0000644000175000017500000000065312506525033012641 0ustar jmmjmm/* XPM */ static char * next_xpm[] = { "16 16 3 1", " c none", ". c #000000000000", "X c #868682828686", " ", " ", " . ", " .. ", " ... ", " .... ", " ........... ", " ............ ", " ...........XX ", " XXXXX....XX ", " ...XX ", " ..XX ", " .XX ", " X ", " ", " "}; fbi-2.10/xpm/unknown.xpm0000644000175000017500000000240312506525033013355 0ustar jmmjmm/* XPM */ static char * unknown_xpm[] = { "32 32 4 1", " c none", ". c #000000000000", "X c #861782078617", "o c #FFFFFFFFFFFF", " ", " ", " ", " ......... ", " ..........X ", " ...Xooooo..XX ", " ..o.Xooooo..XX ", " ..oo.Xooooo..XX ", " ..ooo.Xooooo..XX ", " ..oooo.Xooooo..XX ", " ..ooooo.Xooooo..XX ", " .........Xooooo..XX ", " ..XXXXXXXXooooo..XX ", " ..ooooooooooooo..XX ", " ..ooooo...ooooo..XX ", " ..oooo.XXX.oooo..XX ", " ..oooo.Xoo.Xooo..XX ", " ..oooooXoo.Xooo..XX ", " ..ooooooo.XXooo..XX ", " ..oooooo.XXoooo..XX ", " ..oooooo.Xooooo..XX ", " ..oooooooXooooo..XX ", " ..oooooo.oooooo..XX ", " ..oooooooXooooo..XX ", " ..ooooooooooooo..XX ", " .................XX ", " ................XXX ", " XXXXXXXXXXXXXXXXXX ", " XXXXXXXXXXXXXXXXX ", " ", " ", " "}; fbi-2.10/xpm/dir.xpm0000644000175000017500000000245112506525033012437 0ustar jmmjmm/* XPM */ static char * dir_xpm[] = { "32 32 6 1", " c none", ". c #000000000000", "X c #FFFFFFFFC71B", "o c #FFFFFFFFFFFF", "O c #FFFFFFFF0000", "+ c #861782078617", " ", " ", " ", " ", " ", " ", " ", " ", " ...... ", " .XXXXXX. ", " .XXXXXXXX. ", " ................... ", " .ooooooooooooooooooo. ", " .oXXXXXXXXXXXXXXXXXXXO. ", " .oXXXXXXXXXXXXXXXXXXXO.+ ", " .oXXXXXXXXXXXXXXXXXXXO.++ ", " .oXXXXXXXXXXXXXXXXXXXO.++ ", " .oXXXXXXXXXXXXXXXXXXXO.++ ", " .oXXXXXXXXXXXXXXXXXXXO.++ ", " .oXXXXXXXXXXXXXXXXXXXO.++ ", " .oXXXXXXXXXXXXXXXXXXXO.++ ", " .oXXXXXXXXXXXXXXXXXXXO.++ ", " .oXXXXXXXXXXXXXXXXXXXO.++ ", " .oXXXXXXXXXXXXXXXXXXXO.++ ", " .oXXXXXXXXXXXXXXXXXXXO.++ ", " .OOOOOOOOOOOOOOOOOOO..++ ", " ....................+++ ", " +++++++++++++++++++++ ", " +++++++++++++++++++ ", " ", " ", " "}; fbi-2.10/xpm/zoomout.xpm0000644000175000017500000000065612506525033013402 0ustar jmmjmm/* XPM */ static char * zoomout_xpm[] = { "16 16 3 1", " c none", ". c #000000000000", "X c #868682828686", " ", " ..... ", " .XXXXX. ", " .XX . ", " .XX . ", " .X .X ", " .X ..... .X ", " .X XXXXX .X ", " .X .X ", " . .XX ", " . ... ", " .....X... ", " XXXXX ... ", " ..X ", " XX ", " "}; fbi-2.10/xpm/cw.xpm0000644000175000017500000000065112506525033012272 0ustar jmmjmm/* XPM */ static char * cw_xpm[] = { "16 16 3 1", " c none", ". c #000000000000", "X c #868682828686", " ", " ", " ...... . ", " ..........X ", " ..XXXXXX...X ", " ..XX ....X ", " ..X .....X ", " ..X XXXXX ", " ..X ", " ..X ", " ... . ", " ... ..X ", " ........XX ", " ......XX ", " XXXXXX ", " "}; fbi-2.10/xpm/file.xpm0000644000175000017500000000240012506525033012572 0ustar jmmjmm/* XPM */ static char * file_xpm[] = { "32 32 4 1", " c none", ". c #000000000000", "X c #861782078617", "o c #FFFFFFFFFFFF", " ", " ", " ", " ......... ", " ..........X ", " ...Xooooo..XX ", " ..o.Xooooo..XX ", " ..oo.Xooooo..XX ", " ..ooo.Xooooo..XX ", " ..oooo.Xooooo..XX ", " ..ooooo.Xooooo..XX ", " .........Xooooo..XX ", " ..XXXXXXXXooooo..XX ", " ..ooooooooooooo..XX ", " ..ooooooooooooo..XX ", " ..ooooooooooooo..XX ", " ..ooooooooooooo..XX ", " ..ooooooooooooo..XX ", " ..ooooooooooooo..XX ", " ..ooooooooooooo..XX ", " ..ooooooooooooo..XX ", " ..ooooooooooooo..XX ", " ..ooooooooooooo..XX ", " ..ooooooooooooo..XX ", " ..ooooooooooooo..XX ", " .................XX ", " ................XXX ", " XXXXXXXXXXXXXXXXXX ", " XXXXXXXXXXXXXXXXX ", " ", " ", " "}; fbi-2.10/xpm/prev.xpm0000644000175000017500000000065512506525033012641 0ustar jmmjmm/* XPM */ static char * prev_xpm[] = { "16 16 3 1", " c none", ". c #000000000000", "X c #868682828686", " ", " ", " . ", " ..X ", " ...X ", " ....X ", " ........... ", " ............X ", " ...........X ", " ....XXXXXXX ", " ...X ", " ..X ", " .X ", " X ", " ", " "}; fbi-2.10/xpm/ccw.xpm0000644000175000017500000000065212506525033012436 0ustar jmmjmm/* XPM */ static char * ccw_xpm[] = { "16 16 3 1", " c none", ". c #000000000000", "X c #868682828686", " ", " ", " . ...... ", " .......... ", " ...XXXXXX.. ", " .... .. ", " ..... ..X ", " XXXXX ..X ", " ..X ", " ..X ", " . ...X ", " .. ...XX ", " ........XX ", " ......XX ", " XXXXXX ", " "}; fbi-2.10/xpm/fliph.xpm0000644000175000017500000000065412506525033012766 0ustar jmmjmm/* XPM */ static char * fliph_xpm[] = { "16 16 3 1", " c none", ". c #000000000000", "X c #868682828686", " . . ", " ..X .X ", " ...X .X ", "............. ", ".............X ", " ...XXX.XXXXXX ", " ..X .X ", " .X .X . ", " X .X .. ", " .X ... ", " ............. ", " .............X", " .XXX...XX", " .X ..XX ", " .X .XX ", " X X "}; fbi-2.10/xpm/exit.xpm0000644000175000017500000000065312506525033012634 0ustar jmmjmm/* XPM */ static char * exit_xpm[] = { "16 16 3 1", " c none", ". c #000000000000", "X c #861782078617", " ", " ", " .. ", " ..X ", " . ..X . ", " ..X ..X .. ", " ..X ..X .. ", " ..X ..X ..X ", " ..X ..X ..X ", " ..X XX ..X ", " ..X ..X ", " .. ..XX ", " ........XX ", " ......XX ", " XXXXXX ", " "}; fbi-2.10/xpm/question.xpm0000644000175000017500000000235712506525033013535 0ustar jmmjmm/* XPM */ static char * question_xpm[] = { "32 32 3 1", " c none", ". c #000000000000", "X c #861782078617", " ", " ", " ", " ", " ", " ", " ...... ", " ......... ", " ....XX.... ", " ....XX X... ", " ...XX ...X ", " ...X ....X ", " XXX ...XX ", " ....X ", " ....XX ", " ...XX ", " ...XX ", " ...X ", " ...X ", " ...X ", " XXX ", " ", " ... ", " ...X ", " ...X ", " XXX ", " ", " ", " ", " ", " ", " "}; fbi-2.10/desktop.c0000644000175000017500000001457112506525033012152 0ustar jmmjmm/* * some code to handle desktop files * http://www.freedesktop.org/Standards/desktop-entry-spec * * This is really very simple and basic: next to no locale handling, * no caching, no other clever tricks ... * ida + fbi only use the Comment= entry of .directory files. * * (c) 2004 Gerd Hoffmann * */ #include #include #include #include #include #include #include #include #include "list.h" #include "desktop.h" extern int debug; /* ------------------------------------------------------------------------- */ /* desktop files are in utf-8 */ static int iconv_string(char *to, char *from, char *src, char *dst, size_t max) { size_t ilen = strlen(src); size_t olen = max-1; iconv_t ic; ic = iconv_open(to,from); if (NULL == ic) return 0; while (ilen > 0) { if (-1 == iconv(ic,&src,&ilen,&dst,&olen)) { /* skip + quote broken byte unless we are out of space */ if (E2BIG == errno) break; if (olen < 4) break; sprintf(dst,"\\x%02x",(int)(unsigned char)src[0]); src += 1; dst += 4; ilen -= 1; olen -= 4; } } dst[0] = 0; iconv_close(ic); return max-1 - olen; } int utf8_to_locale(char *src, char *dst, size_t max) { char *codeset = nl_langinfo(CODESET); return iconv_string(codeset, "UTF-8", src, dst, max); } int locale_to_utf8(char *src, char *dst, size_t max) { char *codeset = nl_langinfo(CODESET); return iconv_string("UTF-8", codeset, src, dst, max); } /* ------------------------------------------------------------------------- */ /* read/write desktop files */ struct desktop_line { struct list_head next; char line[1024]; }; static int read_file(char *filename, struct list_head *file) { struct desktop_line *l; int len,count = 0; FILE *fp; INIT_LIST_HEAD(file); fp = fopen(filename,"r"); if (NULL == fp) { if (debug) fprintf(stderr,"open %s: %s\n",filename,strerror(errno)); return 0; } for (;;) { l = malloc(sizeof(*l)); memset(l,0,sizeof(*l)); if (NULL == fgets(l->line,sizeof(l->line),fp)) { free(l); break; } len = strlen(l->line); if (l->line[len-1] == '\n') l->line[len-1] = 0; list_add_tail(&l->next,file); count++; } fclose(fp); return count; } static int write_file(char *filename, struct list_head *file) { struct desktop_line *l; struct list_head *item; FILE *fp; fp = fopen(filename,"w"); if (NULL == fp) { fprintf(stderr,"open %s: %s\n",filename,strerror(errno)); return 0; } list_for_each(item,file) { l = list_entry(item, struct desktop_line, next); fprintf(fp,"%s\n",l->line); } fclose(fp); return 0; } static int dump_file(struct list_head *file) { struct desktop_line *l; struct list_head *item; fprintf(stderr,"\n"); fprintf(stderr,"+--------------------\n"); list_for_each(item,file) { l = list_entry(item, struct desktop_line, next); fprintf(stderr,"| %s\n",l->line); } return 0; } static int free_file(struct list_head *file) { struct desktop_line *l; while (!list_empty(file)) { l = list_entry(file->next, struct desktop_line, next); list_del(&l->next); free(l); } return 0; } /* ------------------------------------------------------------------------- */ static char* get_entry(struct list_head *file, char *entry) { struct desktop_line *l; struct list_head *item; int in_desktop_entry = 0; int len = strlen(entry); list_for_each(item,file) { l = list_entry(item, struct desktop_line, next); if (0 == strcmp(l->line,"[Desktop Entry]")) { in_desktop_entry = 1; continue; } if (0 == strncmp(l->line,"[",1)) { in_desktop_entry = 0; continue; } if (!in_desktop_entry) continue; if (0 == strncmp(l->line,entry,len)) return l->line+len; } return NULL; } /* ------------------------------------------------------------------------- */ static int add_line(struct list_head *file, char *line) { struct desktop_line *add; add = malloc(sizeof(*add)); memset(add,0,sizeof(*add)); snprintf(add->line,sizeof(add->line),"%s",line); list_add_tail(&add->next,file); return 0; } static int add_entry(struct list_head *file, char *entry, char *value) { struct desktop_line *l,*add; struct list_head *item; list_for_each(item,file) { l = list_entry(item, struct desktop_line, next); if (0 != strcmp(l->line,"[Desktop Entry]")) continue; add = malloc(sizeof(*add)); memset(add,0,sizeof(*add)); snprintf(add->line,sizeof(add->line),"%s%s",entry,value); list_add(&add->next,item); return 0; } return -1; } static int set_entry(struct list_head *file, char *type, char *entry, char *value) { struct desktop_line *l; struct list_head *item; int in_desktop_entry = 0; int len = strlen(entry); list_for_each(item,file) { l = list_entry(item, struct desktop_line, next); if (0 == strcmp(l->line,"[Desktop Entry]")) { in_desktop_entry = 1; continue; } if (0 == strncmp(l->line,"[",1)) { in_desktop_entry = 0; continue; } if (!in_desktop_entry) continue; if (0 == strncmp(l->line,entry,len)) { snprintf(l->line,sizeof(l->line),"%s%s",entry,value); return 0; } } if (0 != add_entry(file,entry,value)) { add_line(file,"[Desktop Entry]"); add_entry(file,"Type=",type); add_entry(file,entry,value); } return 0; } /* ------------------------------------------------------------------------- */ /* public interface */ int desktop_read_entry(char *filename, char *entry, char *dest, size_t max) { struct list_head file; char *value; int rc = 0; read_file(filename,&file); if (debug) dump_file(&file); value = get_entry(&file,entry); if (NULL != value) { rc = utf8_to_locale(value,dest,max); if (rc && debug) fprintf(stderr,"# %s\n",dest); }; free_file(&file); return rc; } int desktop_write_entry(char *filename, char *type, char *entry, char *value) { struct list_head file; char utf8[1024]; read_file(filename,&file); locale_to_utf8(value,utf8,sizeof(utf8)); set_entry(&file,"Directory",entry,utf8); write_file(filename,&file); free_file(&file); return 0; } fbi-2.10/fb-gui.c0000644000175000017500000003637212506525033011655 0ustar jmmjmm#include #include #include #include #include #include #include #include #include #include #include #include "fbtools.h" #include "dither.h" #include "fb-gui.h" /* public */ int visible = 1; static int ys = 3; static int xs = 10; /* ---------------------------------------------------------------------- */ /* shadow framebuffer -- internals */ static float p_gamma = 1; static unsigned short p_red[256], p_green[256], p_blue[256]; static struct fb_cmap p_cmap = { 0, 256, p_red, p_green, p_blue }; static int32_t s_lut_transp[256], s_lut_red[256], s_lut_green[256], s_lut_blue[256]; static unsigned char **shadow; static unsigned int *sdirty,swidth,sheight; static unsigned short calc_gamma(int n, int max) { int ret = 65535.0 * pow((float)n/(max), 1 / p_gamma); if (ret > 65535) ret = 65535; if (ret < 0) ret = 0; return ret; } static void linear_palette(int r, int g, int b) { int i, size; size = 256 >> (8 - r); for (i = 0; i < size; i++) p_red[i] = calc_gamma(i,size); p_cmap.len = size; size = 256 >> (8 - g); for (i = 0; i < size; i++) p_green[i] = calc_gamma(i,size); if (p_cmap.len < size) p_cmap.len = size; size = 256 >> (8 - b); for (i = 0; i < size; i++) p_blue[i] = calc_gamma(i,size); if (p_cmap.len < size) p_cmap.len = size; } static void dither_palette(int r, int g, int b) { int rs, gs, bs, i; rs = 256 / (r - 1); gs = 256 / (g - 1); bs = 256 / (b - 1); for (i = 0; i < 256; i++) { p_red[i] = calc_gamma(rs * ((i / (g * b)) % r), 255); p_green[i] = calc_gamma(gs * ((i / b) % g), 255); p_blue[i] = calc_gamma(bs * ((i) % b), 255); } p_cmap.len = 256; } static void shadow_lut_init_one(int32_t *lut, int bits, int shift) { int i; if (bits > 8) for (i = 0; i < 256; i++) lut[i] = (i << (bits + shift - 8)); else for (i = 0; i < 256; i++) lut[i] = (i >> (8 - bits)) << shift; } static void shadow_lut_init(int depth) { if (fb_var.red.length && fb_var.green.length && fb_var.blue.length) { /* fb_var.{red|green|blue} looks sane, use it */ shadow_lut_init_one(s_lut_transp, fb_var.transp.length, fb_var.transp.offset); shadow_lut_init_one(s_lut_red, fb_var.red.length, fb_var.red.offset); shadow_lut_init_one(s_lut_green, fb_var.green.length, fb_var.green.offset); shadow_lut_init_one(s_lut_blue, fb_var.blue.length, fb_var.blue.offset); } else { /* fallback */ int i; switch (depth) { case 15: for (i = 0; i < 256; i++) { s_lut_red[i] = (i & 0xf8) << 7; /* bits -rrrrr-- -------- */ s_lut_green[i] = (i & 0xf8) << 2; /* bits ------gg ggg----- */ s_lut_blue[i] = (i & 0xf8) >> 3; /* bits -------- ---bbbbb */ } break; case 16: for (i = 0; i < 256; i++) { s_lut_red[i] = (i & 0xf8) << 8; /* bits rrrrr--- -------- */ s_lut_green[i] = (i & 0xfc) << 3; /* bits -----ggg ggg----- */ s_lut_blue[i] = (i & 0xf8) >> 3; /* bits -------- ---bbbbb */ } break; case 32: for (i = 0; i < 256; i++) { s_lut_transp[i] = i << 24; /* byte a--- */ } case 24: for (i = 0; i < 256; i++) { s_lut_red[i] = i << 16; /* byte -r-- */ s_lut_green[i] = i << 8; /* byte --g- */ s_lut_blue[i] = i; /* byte ---b */ } break; } } } static void shadow_render_line(int line, unsigned char *dest, char unsigned *buffer) { uint8_t *ptr = (void*)dest; uint16_t *ptr2 = (void*)dest; uint32_t *ptr4 = (void*)dest; int x; switch (fb_var.bits_per_pixel) { case 8: dither_line(buffer, ptr, line, swidth); break; case 15: case 16: for (x = 0; x < swidth; x++) { ptr2[x] = s_lut_red[buffer[x*3]] | s_lut_green[buffer[x*3+1]] | s_lut_blue[buffer[x*3+2]]; } break; case 24: for (x = 0; x < swidth; x++) { ptr[3*x+2] = buffer[3*x+0]; ptr[3*x+1] = buffer[3*x+1]; ptr[3*x+0] = buffer[3*x+2]; } break; case 32: for (x = 0; x < swidth; x++) { ptr4[x] = s_lut_transp[255] | s_lut_red[buffer[x*3]] | s_lut_green[buffer[x*3+1]] | s_lut_blue[buffer[x*3+2]]; } break; } } /* ---------------------------------------------------------------------- */ /* shadow framebuffer -- management interface */ void shadow_render(void) { unsigned int offset = 0; int i; if (!visible) return; for (i = 0; i < sheight; i++, offset += fb_fix.line_length) { if (0 == sdirty[i]) continue; shadow_render_line(i, fb_mem + offset, shadow[i]); sdirty[i] = 0; } } void shadow_clear_lines(int first, int last) { int i; for (i = first; i <= last; i++) { memset(shadow[i],0,3*swidth); sdirty[i]++; } } void shadow_clear(void) { shadow_clear_lines(0, sheight-1); } void shadow_set_dirty(void) { int i; for (i = 0; i < sheight; i++) sdirty[i]++; } void shadow_set_palette(int fd) { if (fb_fix.visual != FB_VISUAL_DIRECTCOLOR && fb_var.bits_per_pixel != 8) return; if (-1 == ioctl(fd,FBIOPUTCMAP,&p_cmap)) { perror("ioctl FBIOPUTCMAP"); exit(1); } } void shadow_init(void) { int i; /* init shadow fb */ swidth = fb_var.xres; sheight = fb_var.yres; shadow = malloc(sizeof(unsigned char*) * sheight); sdirty = malloc(sizeof(unsigned int) * sheight); memset(sdirty,0, sizeof(unsigned int) * sheight); for (i = 0; i < sheight; i++) shadow[i] = malloc(swidth*3); shadow_clear(); /* init rendering */ switch (fb_var.bits_per_pixel) { case 8: dither_palette(8, 8, 4); init_dither(8, 8, 4, 2); dither_line = dither_line_color; break; case 15: case 16: if (fb_var.green.length == 5) { shadow_lut_init(15); if (fb_fix.visual == FB_VISUAL_DIRECTCOLOR) linear_palette(5,5,5); } else { shadow_lut_init(16); if (fb_fix.visual == FB_VISUAL_DIRECTCOLOR) linear_palette(5,6,5); } break; case 24: if (fb_fix.visual == FB_VISUAL_DIRECTCOLOR) linear_palette(8,8,8); break; case 32: if (fb_fix.visual == FB_VISUAL_DIRECTCOLOR) linear_palette(8,8,8); shadow_lut_init(24); break; default: fprintf(stderr, "Oops: %i bit/pixel ???\n", fb_var.bits_per_pixel); exit(1); } } void shadow_fini(void) { int i; if (!shadow) return; for (i = 0; i < sheight; i++) free(shadow[i]); free(shadow); free(sdirty); } /* ---------------------------------------------------------------------- */ /* shadow framebuffer -- drawing interface */ static void shadow_setpixel(int x, int y) { unsigned char *dest = shadow[y] + 3*x; if (x < 0) return; if (x >= swidth) return; if (y < 0) return; if (y >= sheight) return; *(dest++) = 255; *(dest++) = 255; *(dest++) = 255; sdirty[y]++; } void shadow_draw_line(int x1, int x2, int y1,int y2) { int x,y,h; float inc; if (x2 < x1) h = x2, x2 = x1, x1 = h; if (y2 < y1) h = y2, y2 = y1, y1 = h; if (x2 - x1 < y2 - y1) { inc = (float)(x2-x1)/(float)(y2-y1); for (y = y1; y <= y2; y++) { x = x1 + inc * (y - y1); shadow_setpixel(x,y); } } else { inc = (float)(y2-y1)/(float)(x2-x1); for (x = x1; x <= x2; x++) { y = y1 + inc * (x - x1); shadow_setpixel(x,y); } } } void shadow_draw_rect(int x1, int x2, int y1,int y2) { shadow_draw_line(x1, x2, y1, y1); shadow_draw_line(x1, x2, y2, y2); shadow_draw_line(x1, x1, y1, y2); shadow_draw_line(x2, x2, y1, y2); } void shadow_draw_rgbdata(int x, int y, int pixels, unsigned char *rgb) { unsigned char *dest = shadow[y] + 3*x; memcpy(dest,rgb,3*pixels); sdirty[y]++; } void shadow_merge_rgbdata(int x, int y, int pixels, int weight, unsigned char *rgb) { unsigned char *dest = shadow[y] + 3*x; int i = 3*pixels; weight = weight * 256 / 100; while (i-- > 0) *(dest++) += *(rgb++) * weight >> 8; sdirty[y]++; } void shadow_darkify(int x1, int x2, int y1,int y2, int percent) { unsigned char *ptr; int x,y,h; if (x2 < x1) h = x2, x2 = x1, x1 = h; if (y2 < y1) h = y2, y2 = y1, y1 = h; if (x1 < 0) x1 = 0; if (x2 >= swidth) x2 = swidth; if (y1 < 0) y1 = 0; if (y2 >= sheight) y2 = sheight; percent = percent * 256 / 100; for (y = y1; y <= y2; y++) { sdirty[y]++; ptr = shadow[y]; ptr += 3*x1; x = 3*(x2-x1+1); while (x-- > 0) { *ptr = (*ptr * percent) >> 8; ptr++; } } } void shadow_reverse(int x1, int x2, int y1,int y2) { unsigned char *ptr; int x,y,h; if (x2 < x1) h = x2, x2 = x1, x1 = h; if (y2 < y1) h = y2, y2 = y1, y1 = h; if (x1 < 0) x1 = 0; if (x2 >= swidth) x2 = swidth; if (y1 < 0) y1 = 0; if (y2 >= sheight) y2 = sheight; for (y = y1; y <= y2; y++) { sdirty[y]++; ptr = shadow[y]; for (x = x1; x <= x2; x++) { ptr[3*x+0] = 255-ptr[3*x+0]; ptr[3*x+1] = 255-ptr[3*x+1]; ptr[3*x+2] = 255-ptr[3*x+2]; } } } /* ---------------------------------------------------------------------- */ /* shadow framebuffer -- text rendering */ static void shadow_draw_glyph(FT_Bitmap *bitmap, int sx, int sy) { unsigned char *src,*dst; unsigned int bit; int x,y; src = bitmap->buffer; for (y = 0; y < bitmap->rows; y++, src += bitmap->pitch) { if (sy+y < 0) continue; if (sy+y >= sheight) continue; sdirty[sy+y]++; dst = shadow[sy+y] + sx*3; switch (bitmap->pixel_mode) { case FT_PIXEL_MODE_MONO: for (x = 0; x < bitmap->width; x++, dst += 3) { if (sx+x < 0) continue; if (sx+x >= swidth) continue; bit = (1 << (7-(x&7))); if (bit & (src[x >> 3])) { dst[0] = 255; dst[1] = 255; dst[2] = 255; } } break; case FT_PIXEL_MODE_GRAY: for (x = 0; x < bitmap->width; x++, dst += 3) { if (sx+x < 0) continue; if (sx+x >= swidth) continue; if (src[x]) { dst[0] += (255-dst[0]) * src[x] / 255; dst[1] += (255-dst[1]) * src[x] / 255; dst[2] += (255-dst[2]) * src[x] / 255; } } break; } } } struct glyph { FT_Glyph glyph; int pos; }; int shadow_draw_string(FT_Face face, int x, int y, wchar_t *str, int align) { struct glyph *glyphs; FT_UInt gi,pgi; FT_Vector delta,pen; FT_Glyph image; FT_BitmapGlyph bit; size_t len; int i,ng,pos; int kerning; len = wcslen(str); glyphs = malloc(sizeof(*glyphs) * len); memset(glyphs,0,sizeof(*glyphs) * len); kerning = FT_HAS_KERNING(face); pgi = 0; for (ng = 0, pos = 0, i = 0; str[i] != 0; i++) { gi = FT_Get_Char_Index(face, str[i]); if (kerning && pgi && gi) { FT_Get_Kerning(face,pgi,gi,FT_KERNING_DEFAULT,&delta); pos += delta.x; } glyphs[ng].pos = pos; if (0 != FT_Load_Glyph(face, gi, FT_LOAD_DEFAULT)) continue; if (0 != FT_Get_Glyph(face->glyph, &glyphs[ng].glyph)) continue; pos += face->glyph->advance.x; pgi = gi; ng++; } switch(align) { case -1: /* left */ break; case 0: /* center */ x -= pos >> 7; break; case 1: /* right */ x -= pos >> 6; break; } pen.x = 0; pen.y = 0; for (i = 0; i < ng; i++) { image = glyphs[i].glyph; if (0 != FT_Glyph_To_Bitmap(&image,FT_RENDER_MODE_NORMAL,&pen,0)) continue; bit = (FT_BitmapGlyph)image; shadow_draw_glyph(&bit->bitmap, x + bit->left + (glyphs[i].pos >> 6), y - bit->top); if (image != glyphs[i].glyph) FT_Done_Glyph(image); } for (i = 0; i < ng; i++) FT_Done_Glyph(glyphs[i].glyph); free(glyphs); return pos >> 6; } void shadow_draw_string_cursor(FT_Face face, int x, int y, wchar_t *str, int pos) { wchar_t save; int len, left, width, y1, y2; len = wcslen(str); if (pos >= len) { left = shadow_draw_string(face, x, y, str, -1); width = shadow_draw_string(face, x+left, y, L" ", -1); } else { save = str[pos]; str[pos] = 0; left = shadow_draw_string(face, x, y, str, -1); str[pos] = save; save = str[pos+1]; str[pos+1] = 0; width = shadow_draw_string(face, x+left, y, str+pos, -1); str[pos+1] = save; shadow_draw_string(face, x+left+width, y, str+pos+1, -1); } y2 = y - (face->size->metrics.descender >> 6) -1; y1 = y2 - (face->size->metrics.height >> 6) +1; shadow_reverse(left,left+width,y1,y2); } void shadow_draw_text_box(FT_Face face, int x, int y, int percent, wchar_t *lines[], unsigned int count) { unsigned int i,len,max, x1, x2, y1, y2; if (!visible) return; max = 0; for (i = 0; i < count; i++) { len = wcslen(lines[i]); if (max < len) max = len; } FT_Load_Glyph(face, FT_Get_Char_Index(face, 'x'), FT_LOAD_DEFAULT); x1 = x; x2 = x + max * (face->glyph->advance.x >> 6); y1 = y; y2 = y + count * (face->size->metrics.height >> 6); x += xs; x2 += 2*xs; y += ys; y2 += 2*ys; y += (face->size->metrics.height >> 6); y += (face->size->metrics.descender >> 6); shadow_darkify(x1, x2, y1, y2, percent); shadow_draw_rect(x1, x2, y1, y2); for (i = 0; i < count; i++) { shadow_draw_string(face, x, y, lines[i], -1); y += (face->size->metrics.height >> 6); } } /* ---------------------------------------------------------------------- */ /* fontconfig + freetype font rendering */ static FT_Library freetype; void font_init(void) { int rc; FcInit(); rc = FT_Init_FreeType(&freetype); if (rc) { fprintf(stderr,"FT_Init_FreeType() failed\n"); exit(1); } } FT_Face font_open(char *fcname) { FcResult result = 0; FT_Face face = NULL; FcPattern *pattern,*match; char *fontname,*h; FcChar8 *filename; double pixelsize; int rc; /* parse + match font name */ pattern = FcNameParse(fcname); FcConfigSubstitute(NULL, pattern, FcMatchPattern); FcDefaultSubstitute(pattern); match = FcFontMatch (0, pattern, &result); FcPatternDestroy(pattern); if (FcResultMatch != result) return NULL; fontname = FcNameUnparse(match); h = strchr(fontname, ':'); if (h) *h = 0; /* try get the face directly */ result = FcPatternGetFTFace(match, FC_FT_FACE, 0, &face); if (FcResultMatch == result) { fprintf(stderr,"using \"%s\", face=%p\n",fontname,face); return face; } /* failing that use the filename */ result = FcPatternGetString (match, FC_FILE, 0, &filename); if (FcResultMatch == result) { result = FcPatternGetDouble(match, FC_PIXEL_SIZE, 0, &pixelsize); if (FcResultMatch != result) pixelsize = 16; fprintf(stderr,"using \"%s\", pixelsize=%.2lf file=%s\n", fontname,pixelsize,filename); rc = FT_New_Face (freetype, filename, 0, &face); if (rc) return NULL; FT_Set_Pixel_Sizes(face, 0, (int)pixelsize); return face; } /* oops, didn't work */ return NULL; } /* ---------------------------------------------------------------------- */ /* clear screen (areas) */ void fb_clear_mem(void) { if (visible) fb_memset(fb_mem,0,fb_fix.smem_len); } void fb_clear_screen(void) { if (visible) fb_memset(fb_mem,0,fb_fix.line_length * fb_var.yres); } fbi-2.10/filebutton.c0000644000175000017500000005720212506525033012652 0ustar jmmjmm#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "RegEdit.h" #include "list.h" #include "ida.h" #include "x11.h" #include "icons.h" #include "readers.h" #include "filter.h" #include "viewer.h" #include "selections.h" #include "filebutton.h" #include "fileops.h" #include "idaconfig.h" /*----------------------------------------------------------------------*/ struct fileinfo { struct list_head list; char *path; struct ida_image_info img; Pixmap small; Pixmap large; }; static LIST_HEAD(pcache); static LIST_HEAD(pqueue); static LIST_HEAD(files); static XtWorkProcId pproc; /*----------------------------------------------------------------------*/ static struct fileinfo* fileinfo_cache_add(char *path, struct ida_image_info *img, Pixmap small, Pixmap large) { struct fileinfo *item; item = malloc(sizeof(*item)); memset(item,0,sizeof(*item)); item->path = strdup(path); item->img = *img; item->small = small; item->large = large; list_add_tail(&item->list,&pcache); return item; } static void fileinfo_cache_del(char *path) { struct list_head *item; struct fileinfo *b; list_for_each(item,&pcache) { b = list_entry(item,struct fileinfo,list); if (0 == strcmp(path,b->path)) { list_del(&b->list); free(b); return; } } } static struct fileinfo* fileinfo_cache_get(char *path) { struct list_head *item; struct fileinfo *b; list_for_each(item,&pcache) { b = list_entry(item,struct fileinfo,list); if (0 == strcmp(path,b->path)) return b; } return 0; } /*----------------------------------------------------------------------*/ static void fileinfo_cleanup(struct file_button *file) { switch (file->state) { case 1: file->loader->done(file->wdata); break; case 2: desc_resize.done(file->wdata); break; } file->state = 0; if (file->wimg.data) { free(file->wimg.data); file->wimg.data = NULL; } if (file->simg.data) { free(file->simg.data); file->simg.data = NULL; } if (!list_empty(&file->queue)) { list_del_init(&file->queue); } } static void fileinfo_details(struct file_button *file) { struct ida_image_info *img; struct ida_extra *extra; char buf[80]; img = &file->info->img; snprintf(buf, sizeof(buf), "%dx%d", img->thumbnail ? img->real_width : img->width, img->thumbnail ? img->real_height : img->height); XmStringFree(file->details[DETAIL_SIZE]); file->details[DETAIL_SIZE] = XmStringGenerate(buf, NULL, XmMULTIBYTE_TEXT,NULL); extra = load_find_extra(img, EXTRA_COMMENT); if (extra) { XmStringFree(file->details[DETAIL_COMMENT]); file->details[DETAIL_COMMENT] = XmStringGenerate(extra->data, NULL, XmMULTIBYTE_TEXT,NULL); } XtVaSetValues(file->widget, XmNdetail, file->details, XmNdetailCount, DETAIL_COUNT, NULL); } static Boolean fileinfo_loader(XtPointer clientdata) { struct op_resize_parm resize; struct ida_rect rect; struct list_head *item; struct file_button *file; struct fileinfo *info; Pixmap pix; char blk[512]; FILE *fp; float xs,ys,scale; struct ida_image timg; void *data; if (list_empty(&pqueue)) { /* nothing to do */ pproc = 0; return TRUE; } file = list_entry(pqueue.next, struct file_button, queue); switch (file->state) { case 0: /* ------------------- new file -------------------- */ info = fileinfo_cache_get(file->filename); if (info) { file_set_info(file,info); goto next; } /* open file */ if (NULL == (fp = fopen(file->filename, "r"))) { if (debug) fprintf(stderr,"open %s: %s\n",file->filename, strerror(errno)); goto unknown; } if (debug) fprintf(stderr,"OPENED: %s\n",file->filename); fstat(fileno(fp),&file->st); /* pick loader */ memset(blk,0,sizeof(blk)); fread(blk,1,sizeof(blk),fp); rewind(fp); list_for_each(item,&loaders) { file->loader = list_entry(item, struct ida_loader, list); if (NULL == file->loader->magic) continue; if (0 == memcmp(blk+file->loader->moff,file->loader->magic, file->loader->mlen)) break; file->loader = NULL; } if (NULL == file->loader) { if (debug) fprintf(stderr,"%s: unknown format\n",file->filename); fclose(fp); goto unknown; } /* load image */ file->wdata = file->loader->init(fp, file->filename, 0, &file->wimg.i, 1); if (NULL == file->wdata) { if (debug) fprintf(stderr,"loading %s [%s] FAILED\n", file->filename, file->loader->name); goto unknown; } file->wimg.data = malloc(file->wimg.i.width * file->wimg.i.height * 3); file->state = 1; file->y = 0; return FALSE; case 1: /* ------------------- loading file -------------------- */ if (file->y < file->wimg.i.height) { file->loader->read(file->wimg.data + 3 * file->y * file->wimg.i.width, file->y, file->wdata); file->y++; return FALSE; } file->loader->done(file->wdata); if (debug) fprintf(stderr,"LOADED: %s [%ux%u]\n", file->filename, file->wimg.i.width, file->wimg.i.height); /* resize image */ xs = (float)GET_ICON_LARGE() / file->wimg.i.width; ys = (float)GET_ICON_LARGE() / file->wimg.i.height; scale = (xs < ys) ? xs : ys; resize.width = file->wimg.i.width * scale; resize.height = file->wimg.i.height * scale; if (0 == resize.width) resize.width = 1; if (0 == resize.height) resize.height = 1; rect.x1 = 0; rect.x2 = file->wimg.i.width; rect.y1 = 0; rect.y2 = file->wimg.i.height; file->wdata = desc_resize.init(&file->wimg,&rect,&file->simg.i,&resize); file->simg.data = malloc(file->simg.i.width * file->simg.i.height * 3); file->state = 2; file->y = 0; return FALSE; case 2: /* ------------------- scaling file -------------------- */ if (file->y < file->simg.i.height) { desc_resize.work(&file->wimg,&rect, file->simg.data + 3 * file->simg.i.width * file->y, file->y, file->wdata); file->y++; return FALSE; } desc_resize.done(file->wdata); if (debug) fprintf(stderr,"SCALED: %s [%ux%u]\n", file->filename,file->simg.i.width,file->simg.i.height); /* scale once more (small icon) */ xs = (float)GET_ICON_SMALL() / file->simg.i.width; ys = (float)GET_ICON_SMALL() / file->simg.i.height; scale = (xs < ys) ? xs : ys; resize.width = file->simg.i.width * scale; resize.height = file->simg.i.height * scale; if (0 == resize.width) resize.width = 1; if (0 == resize.height) resize.height = 1; rect.x1 = 0; rect.x2 = file->simg.i.width; rect.y1 = 0; rect.y2 = file->simg.i.height; data = desc_resize.init(&file->simg,&rect,&timg.i,&resize); timg.data = malloc(timg.i.width * timg.i.height * 3); for (file->y = 0; file->y < timg.i.height; file->y++) desc_resize.work(&file->simg,&rect, timg.data + 3 * timg.i.width * file->y, file->y, data); desc_resize.done(data); /* build, cache + install pixmap */ info = fileinfo_cache_add(file->filename,&file->wimg.i, image_to_pixmap(&timg), image_to_pixmap(&file->simg)); file_set_info(file,info); free(timg.data); file->state = 0; goto next; default: /* shouldn't happen */ fprintf(stderr,"Oops: %s:%d\n",__FILE__,__LINE__); exit(1); } unknown: /* generic file icon */ pix = XmGetPixmap(file->screen,"unknown",0,0); file_set_icon(file,pix,pix); next: fileinfo_cleanup(file); return FALSE; } /*----------------------------------------------------------------------*/ void fileinfo_queue(struct file_button *file) { if (NULL == file->queue.next) INIT_LIST_HEAD(&file->queue); if (!list_empty(&file->queue)) { /* already queued */ if (0 == file->state) return; fileinfo_cleanup(file); } file->state = 0; memset(&file->wimg,0,sizeof(file->wimg)); memset(&file->simg,0,sizeof(file->simg)); list_add_tail(&file->queue,&pqueue); if (0 == pproc) pproc = XtAppAddWorkProc(app_context,fileinfo_loader,NULL); } void fileinfo_invalidate(char *filename) { struct file_button *file; struct list_head *item; Pixmap pix; if (debug) fprintf(stderr,"fileinfo invalidate: %s\n",filename); fileinfo_cache_del(filename); list_for_each(item,&files) { file = list_entry(item, struct file_button, global); if (0 != strcmp(file->filename,filename)) continue; if (debug) fprintf(stderr," %p %s\n",file,filename); file->info = NULL; pix = XmGetPixmap(file->screen,"file",0,0); file_set_icon(file,pix,pix); fileinfo_queue(file); } } /*----------------------------------------------------------------------*/ static void container_ops_cb(Widget widget, XtPointer clientdata, XtPointer call_data) { Widget container = clientdata; WidgetList children; Cardinal nchildren,i; XtVaGetValues(container, XmNselectedObjects,&children, XmNselectedObjectCount,&nchildren, NULL); for (i = 0; i < nchildren; i++) { struct stat st; if (-1 == stat(XtName(children[i]),&st)) continue; if (!S_ISREG(st.st_mode)) continue; job_submit(XtName(widget),XtName(children[i]), NULL); } } static void comment_box_cb(Widget widget, XtPointer clientdata, XtPointer calldata) { Widget container = clientdata; XmSelectionBoxCallbackStruct *cd = calldata; WidgetList children; Cardinal nchildren,i; Widget text; char *comment; if (XmCR_OK == cd->reason) { /* TODO */ text = XmSelectionBoxGetChild(widget,XmDIALOG_TEXT); comment = XmTextGetString(text); XtVaGetValues(container, XmNselectedObjects,&children, XmNselectedObjectCount,&nchildren, NULL); for (i = 0; i < nchildren; i++) { struct stat st; if (-1 == stat(XtName(children[i]),&st)) continue; if (!S_ISREG(st.st_mode)) continue; job_submit("comment",XtName(children[i]), comment); } } XtDestroyWidget(XtParent(widget)); } static void container_comment_cb(Widget widget, XtPointer clientdata, XtPointer call_data) { Widget container = clientdata; Widget box,text; WidgetList children; Cardinal nchildren; static struct fileinfo *info; struct ida_extra *extra; char *comment = ""; XtVaGetValues(container, XmNselectedObjects,&children, XmNselectedObjectCount,&nchildren, NULL); switch (nchildren) { case 0: /* nothing to do */ return; case 1: /* get old comment */ info = fileinfo_cache_get(XtName(children[0])); if (!info) /* not a image */ return; extra = load_find_extra(&info->img, EXTRA_COMMENT); if (extra) comment = extra->data; break; default: /* start with a empty comment */ break; } /* dialog box */ box = XmCreatePromptDialog(container,"comment",NULL,0); XtUnmanageChild(XmSelectionBoxGetChild(box,XmDIALOG_HELP_BUTTON)); XmdRegisterEditres(XtParent(box)); XtAddCallback(box,XmNokCallback,comment_box_cb,clientdata); XtAddCallback(box,XmNcancelCallback,comment_box_cb,clientdata); XtAddCallback(XtParent(box),XmNdestroyCallback,destroy_cb,XtParent(box)); text = XmSelectionBoxGetChild(box,XmDIALOG_TEXT); XmTextSetString(text,comment); XmTextSetInsertionPosition(text,strlen(comment)); XtManageChild(box); } void container_menu_ops(Widget menu, Widget container) { Widget push; push = XtVaCreateManagedWidget("rotexif",xmPushButtonWidgetClass,menu,NULL); XtAddCallback(push,XmNactivateCallback,container_ops_cb,container); push = XtVaCreateManagedWidget("rotcw",xmPushButtonWidgetClass,menu,NULL); XtAddCallback(push,XmNactivateCallback,container_ops_cb,container); push = XtVaCreateManagedWidget("rotccw",xmPushButtonWidgetClass,menu,NULL); XtAddCallback(push,XmNactivateCallback,container_ops_cb,container); push = XtVaCreateManagedWidget("comment",xmPushButtonWidgetClass,menu,NULL); XtAddCallback(push,XmNactivateCallback,container_comment_cb,container); } /*----------------------------------------------------------------------*/ void container_resize_eh(Widget widget, XtPointer clientdata, XEvent *event, Boolean *d) { Widget clip,scroll,container; Dimension width, height, ch; clip = widget; scroll = XtParent(widget); XtVaGetValues(scroll,XmNworkWindow,&container,NULL); XtVaGetValues(clip, XtNwidth, &width, XtNheight, &height, NULL); XtVaGetValues(container, XtNheight, &ch, NULL); if (ch < height-5) ch = height-5; XtVaSetValues(container, XtNwidth, width-5, XtNheight,ch, NULL); container_relayout(container); } void container_spatial_cb(Widget widget, XtPointer clientdata, XtPointer call_data) { Widget container = clientdata; WidgetList children; Cardinal nchildren; XtVaSetValues(container, XmNlayoutType, XmSPATIAL, XmNspatialStyle, XmNONE, NULL); nchildren = XmContainerGetItemChildren(container,NULL,&children); if (nchildren) { XtFree((XtPointer)children); /* FIXME: Hmm, why ??? */ XtVaSetValues(container, XmNentryViewType, XmLARGE_ICON, NULL); } container_relayout(container); } void container_detail_cb(Widget widget, XtPointer clientdata, XtPointer call_data) { Widget container = clientdata; XtVaSetValues(container, XmNlayoutType, XmDETAIL, XmNentryViewType, XmSMALL_ICON, NULL); container_relayout(container); } void container_traverse_cb(Widget scroll, XtPointer clientdata, XtPointer call_data) { XmTraverseObscuredCallbackStruct *cd = call_data; if (cd->reason == XmCR_OBSCURED_TRAVERSAL) XmScrollVisible(scroll, cd->traversal_destination, 25, 25); } void container_convert_cb(Widget widget, XtPointer clientdata, XtPointer call_data) { XmConvertCallbackStruct *ccs = call_data; char *file = NULL; Atom *targs; int i,n,len; WidgetList children; Cardinal nchildren; if (ccs->location_data) { Widget item = ccs->location_data; children = &item; nchildren = 1; } else { XtVaGetValues(widget, XmNselectedObjects,&children, XmNselectedObjectCount,&nchildren, NULL); } if (debug) { char *t = !ccs->target ? NULL : XGetAtomName(dpy,ccs->target); char *s = !ccs->selection ? NULL : XGetAtomName(dpy,ccs->selection); fprintf(stderr,"drag: target=%s selection=%s [%d files,%p]\n", t, s, nchildren, ccs->location_data); if (t) XFree(t); if (s) XFree(s); } if ((ccs->target == XA_TARGETS) || (ccs->target == _MOTIF_CLIPBOARD_TARGETS) || (ccs->target == _MOTIF_EXPORT_TARGETS)) { targs = (Atom*)XtMalloc(sizeof(Atom)*8); n = 0; if (nchildren >= 1) { targs[n++] = MIME_TEXT_URI_LIST; } if (1 == nchildren) { targs[n++] = XA_FILE_NAME; targs[n++] = XA_FILE; targs[n++] = _NETSCAPE_URL; targs[n++] = XA_STRING; } ccs->value = targs; ccs->length = n; ccs->type = XA_ATOM; ccs->format = 32; ccs->status = XmCONVERT_MERGE; return; } if (ccs->target == _MOTIF_DEFERRED_CLIPBOARD_TARGETS) { targs = (Atom*)XtMalloc(sizeof(Atom)*8); n = 0; ccs->value = targs; ccs->length = n; ccs->type = XA_ATOM; ccs->format = 32; ccs->status = XmCONVERT_DONE; } if ((ccs->target == _MOTIF_LOSE_SELECTION) || (ccs->target == XA_DONE)) { /* free stuff */ ccs->value = NULL; ccs->length = 0; ccs->type = XA_INTEGER; ccs->format = 32; ccs->status = XmCONVERT_DONE; return; } if (ccs->target == XA_FILE_NAME || ccs->target == XA_FILE || ccs->target == XA_STRING) { file = XtMalloc(strlen(XtName(children[0])+1)); strcpy(file,XtName(children[0])); ccs->value = file; ccs->length = strlen(file); ccs->type = XA_STRING; ccs->format = 8; ccs->status = XmCONVERT_DONE; return; } if (ccs->target == _NETSCAPE_URL || ccs->target == MIME_TEXT_URI_LIST) { for (i = 0, len = 0; i < nchildren; i++) len += strlen(XtName(children[i])); file = XtMalloc(len + 8 * nchildren); for (i = 0, len = 0; i < nchildren; i++) len += sprintf(file+len,"file:%s\n",XtName(children[i])); ccs->value = file; ccs->length = len; ccs->type = XA_STRING; ccs->format = 8; ccs->status = XmCONVERT_DONE; return; } ccs->status = XmCONVERT_DEFAULT; } static void container_copy_cb(Widget widget, XtPointer clientdata, XtPointer call_data) { Widget container = clientdata; XmeClipboardSource(container,XmCOPY,XtLastTimestampProcessed(dpy)); } static void container_paste_cb(Widget widget, XtPointer clientdata, XtPointer call_data) { Widget container = clientdata; XmeClipboardSink(container,XmCOPY,NULL); } static void container_del_cb(Widget widget, XtPointer clientdata, XtPointer call_data) { Widget container = clientdata; WidgetList children,list; Cardinal nchildren,i; XtVaGetValues(container, XmNselectedObjects,&children, XmNselectedObjectCount,&nchildren, NULL); list = malloc(sizeof(Widget*)*nchildren); memcpy(list,children,sizeof(Widget*)*nchildren); XtVaSetValues(container, XmNselectedObjectCount,0, NULL); XtUnmanageChildren(list,nchildren); for (i = 0; i < nchildren; i++) XtDestroyWidget(list[i]); free(list); } void container_menu_edit(Widget menu, Widget container, int cut, int copy, int paste, int del) { Widget push; #if 0 if (cut) { push = XtVaCreateManagedWidget("cut",xmPushButtonWidgetClass,menu,NULL); XtAddCallback(push,XmNactivateCallback, container_cut_cb,container); } #endif if (copy) { push = XtVaCreateManagedWidget("copy",xmPushButtonWidgetClass,menu,NULL); XtAddCallback(push,XmNactivateCallback, container_copy_cb,container); } if (paste) { push = XtVaCreateManagedWidget("paste",xmPushButtonWidgetClass,menu,NULL); XtAddCallback(push,XmNactivateCallback, container_paste_cb,container); } if (del) { push = XtVaCreateManagedWidget("del",xmPushButtonWidgetClass,menu,NULL); XtAddCallback(push,XmNactivateCallback, container_del_cb,container); } } void container_menu_view(Widget menu, Widget container) { Widget push; push = XtVaCreateManagedWidget("details",xmPushButtonWidgetClass,menu,NULL); XtAddCallback(push,XmNactivateCallback, container_detail_cb,container); push = XtVaCreateManagedWidget("spatial",xmPushButtonWidgetClass,menu,NULL); XtAddCallback(push,XmNactivateCallback, container_spatial_cb,container); } void container_relayout(Widget container) { Widget clip = XtParent(container); WidgetList children; Cardinal nchildren; Dimension wwidth,wheight; Dimension iwidth,iheight; Position x,y; unsigned char layout,style; int i,margin = 10; XtVaGetValues(container, XmNlayoutType, &layout, XmNspatialStyle, &style, NULL); if (XmSPATIAL != layout || XmNONE != style) { XmContainerRelayout(container); return; } nchildren = XmContainerGetItemChildren(container,NULL,&children); XtVaGetValues(clip, XtNwidth, &wwidth, XtNheight, &wheight, NULL); wwidth -= 5; x = margin; y = margin; for (i = 0; i < nchildren; i++) { if (!XtIsManaged(children[i])) continue; XtVaGetValues(children[i], XtNwidth,&iwidth, XtNheight,&iheight, NULL); if (x > 0 && x + iwidth + margin > wwidth) { /* new row */ x = margin; y += iheight + margin; } XtVaSetValues(children[i], XtNx,x, XtNy,y, XmNpositionIndex,i, NULL); x += iwidth + margin; } if (wheight < y + iheight + margin) wheight = y + iheight + margin; XtVaSetValues(container, XtNwidth, wwidth, XtNheight, wheight, NULL); if (nchildren) XtFree((XtPointer)children); } void container_delwidgets(Widget container) { WidgetList children; Cardinal nchildren; unsigned int i; /* delete widgets */ XtVaSetValues(container, XmNselectedObjectCount,0, NULL); nchildren = XmContainerGetItemChildren(container,NULL,&children); XtUnmanageChildren(children,nchildren); for (i = 0; i < nchildren; i++) XtDestroyWidget(children[i]); if (nchildren) XtFree((XtPointer)children); } /*----------------------------------------------------------------------*/ void file_set_icon(struct file_button *file, Pixmap s, Pixmap l) { Pixmap large, small; Pixel background; if (file->info) return; XtVaGetValues(file->widget, XmNbackground,&background, NULL); small = x11_icon_fit(DisplayOfScreen(file->screen), s, background, GET_ICON_SMALL(), GET_ICON_SMALL()); large = x11_icon_fit(DisplayOfScreen(file->screen), l, background, GET_ICON_LARGE(), GET_ICON_LARGE()); XtVaSetValues(file->widget, XmNsmallIconPixmap, small, XmNlargeIconPixmap, large, NULL); if (file->small) XFreePixmap(DisplayOfScreen(file->screen),file->small); if (file->large) XFreePixmap(DisplayOfScreen(file->screen),file->large); file->small = small; file->large = large; } void file_set_info(struct file_button *file, struct fileinfo *info) { file->info = NULL; file_set_icon(file,info->small,info->large); file->info = info; fileinfo_details(file); } #if 0 static void file_copy_cb(Widget widget, XtPointer clientdata, XtPointer call_data) { struct file_button *file = clientdata; XmeClipboardSource(file->widget,XmCOPY,XtLastTimestampProcessed(dpy)); } #endif /*----------------------------------------------------------------------*/ int file_cmp_alpha(const struct file_button *aa, const struct file_button *bb) { if (S_ISDIR(aa->st.st_mode) != S_ISDIR(bb->st.st_mode)) return S_ISDIR(aa->st.st_mode) ? -1 : 1; return strcmp(aa->basename,bb->basename); } static void file_destroy_cb(Widget widget, XtPointer clientdata, XtPointer call_data) { struct file_button *file = clientdata; int i; if (debug) fprintf(stderr,"file: del %p [%s]\n",file,file->filename); if (NULL != file->queue.next) fileinfo_cleanup(file); if (file->basename) free(file->basename); if (file->filename) free(file->filename); XtVaSetValues(file->widget, XmNsmallIconPixmap, XmUNSPECIFIED_PIXMAP, XmNlargeIconPixmap, XmUNSPECIFIED_PIXMAP, NULL); if (file->small) XFreePixmap(DisplayOfScreen(file->screen),file->small); if (file->large) XFreePixmap(DisplayOfScreen(file->screen),file->large); if (file->label) XmStringFree(file->label); for (i = 0; i < DETAIL_COUNT; i++) if (file->details[i]) XmStringFree(file->details[i]); list_del(&file->global); list_del(&file->window); free(file); } int file_createwidgets(Widget parent, struct file_button *file) { struct fileinfo *info; Pixmap pix; Arg args[8]; int i, n = 0; if (debug) fprintf(stderr,"file: new %p [%s]\n",file,file->filename); file->screen = XtScreen(parent); file->label = XmStringGenerate(file->basename, NULL, XmMULTIBYTE_TEXT,NULL); for (i = 0; i < DETAIL_COUNT; i++) file->details[i] = XmStringGenerate("-", NULL, XmMULTIBYTE_TEXT,NULL); XtSetArg(args[n], XmNlabelString, file->label); n++; XtSetArg(args[n], XmNdetail, file->details); n++; XtSetArg(args[n], XmNdetailCount, DETAIL_COUNT); n++; file->widget = XmCreateIconGadget(parent,file->filename,args,n); XtAddCallback(file->widget,XtNdestroyCallback,file_destroy_cb,file); list_add_tail(&file->global,&files); info = fileinfo_cache_get(file->filename); if (info) { file_set_info(file,info); } else { pix = XmGetPixmap(file->screen,"question",0,0); file_set_icon(file,pix,pix); } return 0; } fbi-2.10/ida.man0000644000175000017500000000762712506525033011573 0ustar jmmjmm.TH IDA 1 "(c) 2001-2012 Gerd Hoffmann" "IDA 2.09" "Image viewing and editing program" \# \# .SH NAME ida - image viewing and editing program \# \# .SH SYNOPSIS \fBida\fP [\fIoptions\fP] \fIfile ...\fP \# \# .SH DESCRIPTION .BR Ida is a small and fast application for viewing images. Some basic editing functions are available too. .P You can specify any number of image files as arguments on the command line. Or you can read a single image from stdin by specifying "-" as only argument ("\fIxwd | ida -\fP" works nice for screenshots). \# \# .SH OPTIONS .BR Ida understands the usual toolkit options (-geometry + friends). Additional options are: .TP .B -help print a short help text .TP .BI "-pcd" "\ n" Pick size for PhotoCD images (\fIn = 1 .. 5\fP, default 3). .TP .B -debug Enable debug messages. Also has the side effect that error messages are displayed on stderr only and \fBnot\fP as message box. \# \# .SH "GETTING STARTED" .SS Mouse functions .P With the left mouse button you can creates and edit a selection rectangle. The middle button is used to start drag'n'drop operations. The right button brings up the control window with menus, toolbar and file list. .SS Keyboard Shortcuts .P Many keyboard shortcuts used by .BR xv are available in .BR ida too. If you are familiar with .BR xv if should be easy for you to get started with .BR "ida" "." .P All available keyboard shortcuts are also listed in the menus of the control window. The most important ones are listed below: .TP \fBSPACE\fP Next file. .TP \fBBACKSPACE\fP Previous file. .TP \fBLEFT_ARROW\fP, \fBRIGHT_ARROW\fP, \fBUP_ARROW\fP, \fBDOWN_ARROW\fP Scrolling (hold \fBCtrl\fP key for big steps). .TP \fB+/-\fP Zoom in/out. .TP \fBq\fP Quit. .SS Supported image formats .TP .B Read: \fIBMP\fP (uncompressed), \fIPhotoCD\fP, \fIPPM\fP, \fIXBM\fP, \fIXPM\fP, \fIXWD\fP, \fIGIF\fP, \fIJPEG\fP, \fIPNG\fP, \fITIFF\fP. The last four are supported using the usual libraries, i.e. you need to have them installed at compile time. .TP .B Write: \fIJPEG\fP, \fIPNG\fP, \fIPostScript\fP, \fIPPM\fP, \fITIFF\fP. .SS Using drag'n'drop .B Ida is a motif application and thus supports the motif drag'n'drop protocol in both directions. The \fBxdnd\fP protocol is supported too, but only in one direction (receive drops). .P .BR Ida uses the middle mouse button to start a drag'n'drop operation (as the motif style guide suggests). This works for the main window and the file buttons within the file browser. .P .B Motif applications should have absolutely no problems to deal with .BR "ida" "'s" drag'n'drop support. You can drop images into some netscape 4.x window -- it imply works. Mozilla accepts motif drops too. .P Interoperation with .B gnome / gtk is good. I can drag files from .BR ida to .BR eeyes and visa versa without problems. File drops from .BR gmc into .BR ida work just fine too. .P Interoperation with .B KDE is bad. cut+paste works most of the time, drag'n'drop often doesn't. The X11 selection handling of the Qt toolkit has a few design bugs and sucks. Basically the troll guys didn't understand what the TARGETS target is good for and violate the ICCCM specs by ignoring it. \# \# .SH "SEE ALSO" .BR xwd (1) \# \# .SH AUTHOR Gerd Hoffmann .BR \# \# .SH COPYRIGHT Copyright (c) 2002-2012 Gerd Hoffmann .P 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. .P 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. .P 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., 675 Mass Ave, Cambridge, MA 02139, USA. fbi-2.10/icons.c0000644000175000017500000000601212506525033011603 0ustar jmmjmm#include #include #include #include #include #include #include #include "icons.h" #include "misc.h" #include "xpm/cw.xpm" #include "xpm/ccw.xpm" #include "xpm/fliph.xpm" #include "xpm/flipv.xpm" #include "xpm/prev.xpm" #include "xpm/next.xpm" #include "xpm/zoomin.xpm" #include "xpm/zoomout.xpm" #include "xpm/exit.xpm" #include "xpm/question.xpm" #include "xpm/dir.xpm" #include "xpm/file.xpm" #include "xpm/unknown.xpm" static void patch_bg(XImage *image, XImage *shape, int width, int height, Pixel bg) { unsigned int x,y; for (y = 0; y < height; y++) for (x = 0; x < width; x++) if (!XGetPixel(shape, x, y)) XPutPixel(image, x, y, bg); } static void add_pixmap(Display *dpy, Pixel bg, char *name, char **data) { XImage *image,*shape; XpmAttributes attr; char sname[32]; memset(&attr,0,sizeof(attr)); XpmCreateImageFromData(dpy,data,&image,&shape,&attr); if (shape) { patch_bg(image,shape,attr.width,attr.height,bg); snprintf(sname,sizeof(sname),"%s_shape",name); XmInstallImage(shape,sname); } XmInstallImage(image,name); } Pixmap x11_icon_fit(Display *dpy, Pixmap icon, unsigned long bg, int width, int height) { Pixmap pix; GC gc; XGCValues values; Window root; unsigned int w,h,b,d; int x,y; XGetGeometry(dpy,icon,&root,&x,&y,&w,&h,&b,&d); pix = XCreatePixmap(dpy,icon,width,height,d); /* fill background */ values.foreground = bg; values.background = bg; values.fill_style = FillSolid; gc = XCreateGC(dpy, icon, GCForeground | GCBackground | GCFillStyle, &values); XFillRectangle(dpy,pix,gc,0,0,width,height); /* blit */ if (w <= width && h <= height) { /* just center ... */ x = (width - w) / 2; y = (height - h) / 2; XCopyArea(dpy,icon,pix,gc,0,0,w,h,x,y); } else { /* must scale down */ #if 0 float xs,ys,scale; xs = (float)width / w; ys = (float)height / h; scale = (xs < ys) ? xs : ys; w = w * scale; h = h * scale; if (0 == w) w = 1; if (0 == h) h = 1; x = (width - w) / 2; y = (height - h) / 2; XCopyArea(dpy,icon,pix,gc,0,0,w,h,x,y); #endif x = (width - w) / 2; y = (height - h) / 2; if (x < 0) x = 0; if (y < 0) y = 0; XCopyArea(dpy,icon,pix,gc,0,0,w,h,0,0); } XFreeGC(dpy, gc); return pix; } void x11_icons_init(Display *dpy, unsigned long bg) { add_pixmap(dpy, bg, "rotcw", cw_xpm); add_pixmap(dpy, bg, "rotccw", ccw_xpm); add_pixmap(dpy, bg, "fliph", fliph_xpm); add_pixmap(dpy, bg, "flipv", flipv_xpm); add_pixmap(dpy, bg, "prev", prev_xpm); add_pixmap(dpy, bg, "next", next_xpm); add_pixmap(dpy, bg, "zoomin", zoomin_xpm); add_pixmap(dpy, bg, "zoomout", zoomout_xpm); add_pixmap(dpy, bg, "exit", exit_xpm); add_pixmap(dpy, bg, "question", question_xpm); add_pixmap(dpy, bg, "dir", dir_xpm); add_pixmap(dpy, bg, "file", file_xpm); add_pixmap(dpy, bg, "unknown", unknown_xpm); } fbi-2.10/mallard_32.xpm0000644000175000017500000000300712506525033012773 0ustar jmmjmm/* XPM */ static char *mallard_test[] = { /* columns rows colors chars-per-pixel */ "32 32 13 1 ", " c #15FF0C300C32", ". c #006232730FBC", "X c #28E91FCB1FCB", "o c #647E309B2445", "O c #0ADC5ADD1E6D", "+ c #5A8056B85431", "@ c white", "# c #FBEEFC94002E", "$ c #A5DCC5AB0C3C", "= c #E838D81BD3EA", "- c #A6DFA3E9A351", "; c None", ": c #409C83D13ABD", /* pixels */ /*white is @%@* */ ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;", ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;", ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;", ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;", ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;", ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;", ";;;;;;....;;;;;;;;;;;;;;;;;;;;;;", ";;;;;......;;;;;;;;;;;;;;;;;;;;;", ";;;;....OOO.;;;;;;;;;;;;;;;;;;;;", ";;;;#OOOOOO.;;;;;;;;;;;;;;;;;;;;", ";;####:OOOO.;;;;;;;;;;;;;;;;;;;;", ";#####:OOO..;;;;;;;;;;;;;;;;;;;;", "#####;O.....;;;;;;;;;;;;;;;;;;;;", "###;;;@@@@@@;;;;;;;;;;;;;;;;;;;;", ";;;;;;@@@@@-+ ;;;;;;; ;;", ";;;;;;@@@=@@+Xo+++++++X ;;;;; ;;", ";;;; X++++=@+o-@@@@@@-+ @", ";;; X Xo+==++-@@@@@@-o X+@@", ";; o-@@@=-++==+++oX X-@@;", ";; X +@@@@@@++@=++++++++ X;;;", ";;X X +@@@@@@@@@@@@@@@@@@;;;;;;", ";; +@@@@@@@@@@@@@@@@@@;;;;;;", ";;X X +@@@@@@@@@@@@@@@;;;;;;;;;", ";;; +@@@@@@@@;;;;oo;;;;;;;;;;", ";;;;;;;;;;;;;;;;;;oo;;;;;;;;;;;;", ";;;;;;;;;;;;;;;;;;oo;;;;;;;;;;;;", ";;;;;;;;;;;;;;;;;;;ooooo;;;;;;;;", ";;;;;;;;;;;;;;;;;;;;;ooo;;;;;;;;", ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;", ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;", ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;", ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;" }; fbi-2.10/filelist.h0000644000175000017500000000016512506525033012313 0ustar jmmjmmvoid filelist_window(void); void filelist_ac(Widget widget, XEvent *event, String *params, Cardinal *num_params); fbi-2.10/fbgs0000755000175000017500000000575112506525033011204 0ustar jmmjmm#!/bin/sh # # PostScript/pdf viewer for the linux framebuffer console # (c) 1999-2012 Gerd Hoffmann # # tmp dir DIR="$(mktemp -dtp ${TMPDIR-/var/tmp} fbgs-XXXXXX)" test -d "$DIR" || exit 1 trap "rm -rf $DIR" EXIT # parse options fbiopts="" gsopts="" passwd="" device="png16m" opt=1 bell="off" helptext="\ This program displays PostScript/pdf files using the linux framebuffer device. It is a simple wrapper script for GhostScript and fbi. usage: fbgs [fbgs options] [fbi options] file -b --bell emit a beep when the document is ready -h --help print this help text -p --password a passed to the PDF -fp --firstpage begins on the page -lp --lastpage stops on the page -c --(no)color pages in color -l pages rendered with 100 dpi -xl pages rendered with 120 dpi -xxl pages rendered with 150 dpi -r --resolution choose resolution of dpi Read the fbgs(1) and fbi(1) manpages for more details. " [ $# -ne 0 ] || set -- -h while test "$opt" = "1"; do case "$1" in # fbgs options -b | --bell) bell="on" shift ;; -h | --help) printf "$helptext" exit 1 ;; -p | --password) password="$2" shift; shift ;; -fp | --firstpage) gsopts="$gsopts -dFirstPage=$2" shift; shift ;; -lp | --lastpage) gsopts="$gsopts -dLastPage=$2" shift; shift ;; -c | --color) device="png16m" shift ;; --nocolor) device="tiffpack" shift ;; -l) gsopts="$gsopts -r100x100" shift ;; -xl) gsopts="$gsopts -r120x120" shift ;; -xxl) gsopts="$gsopts -r150x150" shift ;; -r | --resolution) gsopts="$gsopts -r$2x$2" shift; shift ;; # fbi options without argument -a | --autozoom | \ --autoup | --noautoup | \ --autodown | --noautodown | \ --fitwidth | --nofitwidth | \ --readahead | --noreadahead | \ -v | --verbose | --noverbose | \ -u | --random | --norandom | \ -1 | --once | --noonce) fbiopts="$fbiopts $1" shift ;; # fbi options with one argument -T | --vt | \ -s | --scroll | \ -t | --timeout | \ -g | --gamma | \ -f | --font | \ -d | --device | \ -m | --mode) fbiopts="$fbiopts $1 $2" shift; shift ;; # others options -*) echo "unknown option: $1" exit 1 ;; *) opt=0 ;; esac done if [ ! -f "$1" ]; then echo "fbgs: cannot stat '$1': No such file or directory" exit 1 fi # run ghostscript echo echo "### rendering pages, please wait ... ###" echo gs -dSAFER -dNOPAUSE -dBATCH \ -sPDFPassword="$password" \ -sDEVICE=${device} -sOutputFile=$DIR/ps%03d.tiff \ $gsopts \ "$1" # tell the user we are done :-) if test "$bell" = "on"; then printf "\a" fi # sanity check pages=`ls $DIR/ps*.tiff 2>/dev/null | wc -l` if test "$pages" -eq "0"; then echo echo "Oops: ghostscript wrote no pages?" echo exit 1 fi # show pages fbi $fbiopts -P $DIR/ps*.tiff fbi-2.10/fileops.c0000644000175000017500000000475712506525033012147 0ustar jmmjmm#include #include #include #include #include #include "list.h" #include "ida.h" #include "readers.h" #include "filebutton.h" #include "fileops.h" #include #include "transupp.h" /* Support routines for jpegtran */ #include "jpegtools.h" /*----------------------------------------------------------------------*/ struct jobqueue { struct list_head list; char *op; char *filename; char *args; }; static LIST_HEAD(jobs); static XtWorkProcId jobproc; /*----------------------------------------------------------------------*/ static Boolean job_worker(XtPointer clientdata) { struct jobqueue *job; unsigned int flags = JFLAG_TRANSFORM_IMAGE | JFLAG_TRANSFORM_THUMBNAIL | JFLAG_TRANSFORM_TRIM | JFLAG_UPDATE_ORIENTATION; if (list_empty(&jobs)) { /* nothing to do */ jobproc = 0; return TRUE; } job = list_entry(jobs.next, struct jobqueue, list); /* process job */ if (debug) fprintf(stderr,"job worker: %s %s\n",job->op,job->filename); ptr_busy(); if (0 == strcmp(job->op,"rotexif")) { jpeg_transform_inplace(job->filename, -1/*auto*/, NULL, NULL, 0, flags); } else if (0 == strcmp(job->op,"rotcw")) { jpeg_transform_inplace(job->filename, JXFORM_ROT_90, NULL, NULL, 0, flags); } else if (0 == strcmp(job->op,"rotccw")) { jpeg_transform_inplace(job->filename, JXFORM_ROT_270, NULL, NULL, 0, flags); } else if (0 == strcmp(job->op,"comment")) { jpeg_transform_inplace(job->filename, JXFORM_NONE, job->args, NULL, 0, JFLAG_UPDATE_COMMENT); } else { fprintf(stderr,"job: \"%s\" is *unknown*\n",job->op); } ptr_idle(); fileinfo_invalidate(job->filename); /* cleanup */ list_del(&job->list); free(job->filename); free(job->op); if (job->args) free(job->args); free(job); return FALSE; } /*----------------------------------------------------------------------*/ void job_submit(char *op, char *filename, char *args) { struct jobqueue *job; job = malloc(sizeof(*job)); memset(job,0,sizeof(*job)); job->op = strdup(op); job->filename = strdup(filename); if (args) job->args = strdup(args); list_add_tail(&job->list,&jobs); if (debug) fprintf(stderr,"job submit: %s %s\n",job->op,job->filename); if (0 == jobproc) jobproc = XtAppAddWorkProc(app_context,job_worker,NULL); } fbi-2.10/xdnd.c0000644000175000017500000002170412506525033011432 0ustar jmmjmm/* * basic Xdnd support for Motif 2.x * * Receive drops only. Works fine in parallel with Motif DnD. * * Initiate drags is probably hard do do without breaking Motif DnD or * heavily mucking with the Motif internals. Highlighting seems to be * non-trivial too. * * Usage: * (1) register XdndAction as "Xdnd" * (2) register Widgets using XdndDropSink (acts like XmeDropSink * for Motif DnD) * (3) the transfer callback functions have to call * XdndDropFinished() when they are done (i.e. after calling * XmTransferDone) * * Data transfer is done using the usual Motif 2.x way, using UTM. * Read: XmNdestinationCallback will be called, with * XmDestinationCallbackStruct->selection set to XdndSelection. * * It is up to the application to handle the Xdnd MIME targets * correctly, i.e. accept both "TEXT" and "text/plain" targets for * example. Otherwise Xdnd support shouldn't need much work if Motif * DnD support is present already. * * Known problems: * - Not working with KDE 2.x as they don't provide a TARGETS * target (which IMO is illegal, see ICCCM specs). * */ #include #include #include #include #include #include #include #include #include #include "xdnd.h" /* ---------------------------------------------------------------------- */ int xdnd_debug = 0; static Atom XdndAware; static Atom XdndTypeList; static Atom XdndSelection; static Atom XdndEnter; static Atom XdndPosition; static Atom XdndStatus; static Atom XdndLeave; static Atom XdndDrop; static Atom XdndFinished; static Atom XdndActionCopy; static Atom XdndActionMove; static Atom XdndActionLink; static Atom XdndActionAsk; static Atom XdndActionPrivate; /* ---------------------------------------------------------------------- */ static void XdndInit(Display *dpy) { if (XdndAware) return; XdndAware = XInternAtom(dpy, "XdndAware", False); XdndTypeList = XInternAtom(dpy, "XdndTypeList", False); XdndSelection = XInternAtom(dpy, "XdndSelection", False); /* client messages */ XdndEnter = XInternAtom(dpy, "XdndEnter", False); XdndPosition = XInternAtom(dpy, "XdndPosition", False); XdndStatus = XInternAtom(dpy, "XdndStatus", False); XdndLeave = XInternAtom(dpy, "XdndLeave", False); XdndDrop = XInternAtom(dpy, "XdndDrop", False); XdndFinished = XInternAtom(dpy, "XdndFinished", False); /* actions */ XdndActionCopy = XInternAtom(dpy, "XdndActionCopy", False); XdndActionMove = XInternAtom(dpy, "XdndActionMove", False); XdndActionLink = XInternAtom(dpy, "XdndActionLink", False); XdndActionAsk = XInternAtom(dpy, "XdndActionAsk", False); XdndActionPrivate = XInternAtom(dpy, "XdndActionPrivate", False); } static void init_window(Widget widget) { int version = 4; /* window */ XChangeProperty(XtDisplay(widget),XtWindow(widget), XdndAware, XA_ATOM, 32, PropModeReplace, (XtPointer)&version, 1); /* shell */ while (!XtIsShell(widget)) widget = XtParent(widget); XChangeProperty(XtDisplay(widget),XtWindow(widget), XdndAware, XA_ATOM, 32, PropModeReplace, (XtPointer)&version, 1); XtOverrideTranslations(widget, XtParseTranslationTable ("XdndEnter: Xdnd()\n" "XdndPosition: Xdnd()\n" "XdndLeave: Xdnd()\n" "XdndDrop: Xdnd()")); } static Widget find_window(Widget widget, int wx, int wy, int rx, int ry) { WidgetList children; Cardinal nchildren; Dimension x,y,w,h; Widget found = NULL; int i; nchildren = 0; XtVaGetValues(widget,XtNchildren,&children, XtNnumChildren,&nchildren,NULL); if (xdnd_debug) fprintf(stderr,"findwindow %s\n",XtName(widget)); for (i = nchildren-1; i >= 0; i--) { XtVaGetValues(children[i],XtNx,&x,XtNy,&y, XtNwidth,&w,XtNheight,&h,NULL); if (!XtIsManaged(children[i])) continue; if (XtIsSubclass(children[i],xmGadgetClass)) continue; if (rx < wx+x || rx > wx+x+w) continue; if (ry < wy+y || ry > wy+y+h) continue; found = children[i]; break; } if (found) { if (xdnd_debug) fprintf(stderr," more: %s\n",XtName(found)); return find_window(found,wx+x,wy+y,rx,ry); } if (xdnd_debug) fprintf(stderr," done: %s\n",XtName(widget)); return widget; } static int check_window(Widget widget) { Atom type; int format,rc; unsigned long nitems,rest; unsigned long *ldata; rc = XGetWindowProperty(XtDisplay(widget),XtWindow(widget), XdndAware,0,64,False,AnyPropertyType, &type,&format,&nitems,&rest, (XtPointer)&ldata); XFree(ldata); return rc == Success && nitems > 0; } static XtEnum get_operation(Atom action) { if (XdndActionCopy == action) return XmCOPY; if (XdndActionLink == action) return XmLINK; if (XdndActionMove == action) return XmMOVE; return 0; } static Atom get_action(XtEnum operation) { if (XmCOPY == operation) return XdndActionCopy; if (XmLINK == operation) return XdndActionLink; if (XmMOVE == operation) return XdndActionMove; return None; } static void XdndEvent(Widget widget, XtPointer clientdata, XEvent *event, Boolean *cont) { switch(event->type) { case MapNotify: init_window(widget); break; } } /* ---------------------------------------------------------------------- */ /* * not very nice this way, but as you can hardly have two drags at the * same time with one pointer only it should be fine ... */ static Widget target; static int target_ok,drop_ok; static Window source; static XtEnum operation; void XdndAction(Widget widget, XEvent *event, String *params, Cardinal *num_params) { char *name; XEvent reply; if (NULL == event) return; if (ClientMessage != event->type) return; if (XdndEnter == event->xclient.message_type) { if (xdnd_debug) fprintf(stderr,"Xdnd: Enter: win=0x%lx ver=%ld more=%s\n", event->xclient.data.l[0], event->xclient.data.l[1] >> 24, (event->xclient.data.l[1] & 1) ? "yes" : "no"); } if (XdndPosition == event->xclient.message_type) { source = event->xclient.data.l[0]; target = find_window(widget,0,0, event->xclient.data.l[2] >> 16, event->xclient.data.l[2] & 0xffff); target_ok = check_window(target); if (target_ok) { operation = get_operation(event->xclient.data.l[4]); operation = XmCOPY; /* FIXME */ drop_ok = 1; } else { operation = 0; drop_ok = 0; } if (xdnd_debug) { name = NULL; if (event->xclient.data.l[4]) name=XGetAtomName(XtDisplay(widget),event->xclient.data.l[4]); fprintf(stderr,"Xdnd: Position: win=0x%lx pos=+%ld+%ld ts=%ld " "ac=%s op=%d widget=%s drop=%s\n", event->xclient.data.l[0], event->xclient.data.l[2] >> 16, event->xclient.data.l[2] & 0xffff, event->xclient.data.l[3], name,operation, XtName(target),target_ok ? "yes" : "no"); if (name) XFree(name); } memset(&reply,0,sizeof(reply)); reply.xany.type = ClientMessage; reply.xany.display = XtDisplay(widget); reply.xclient.window = event->xclient.data.l[0]; reply.xclient.message_type = XdndStatus; reply.xclient.format = 32; reply.xclient.data.l[0] = XtWindow(widget); reply.xclient.data.l[1] = drop_ok ? 1 : 0; reply.xclient.data.l[4] = get_action(operation); XSendEvent(XtDisplay(widget),reply.xclient.window,0,0,&reply); } if (XdndDrop == event->xclient.message_type) { source = event->xclient.data.l[0]; if (xdnd_debug) fprintf(stderr,"Xdnd: Drop: win=0x%lx ts=%ld\n", event->xclient.data.l[0], event->xclient.data.l[2]); XmeNamedSink(target,XdndSelection,XmCOPY,NULL, XtLastTimestampProcessed(XtDisplay(widget))); } if (XdndLeave == event->xclient.message_type) { source = 0; if (xdnd_debug) fprintf(stderr,"Xdnd: Leave: win=0x%lx\n", event->xclient.data.l[0]); } } void XdndDropFinished(Widget widget, XmSelectionCallbackStruct *scs) { XEvent reply; if (XdndSelection != scs->selection) return; if (0 == source) return; if (xdnd_debug) fprintf(stderr,"Xdnd: sending Finished (0x%lx)\n",source); memset(&reply,0,sizeof(reply)); reply.xany.type = ClientMessage; reply.xany.display = XtDisplay(widget); reply.xclient.window = source; reply.xclient.message_type = XdndFinished; reply.xclient.format = 32; while (!XtIsShell(widget)) widget = XtParent(widget); reply.xclient.data.l[0] = XtWindow(widget); XSendEvent(XtDisplay(widget),reply.xclient.window,0,0,&reply); source = 0; } void XdndDropSink(Widget widget) { XdndInit(XtDisplay(widget)); if (XtWindow(widget)) init_window(widget); XtAddEventHandler(widget,StructureNotifyMask,True,XdndEvent,NULL); } fbi-2.10/desktop/0000755000175000017500000000000012506525033011776 5ustar jmmjmmfbi-2.10/desktop/ida.desktop0000644000175000017500000000026412506525033014130 0ustar jmmjmm[Desktop Entry] Type=Application Encoding=UTF-8 Name=ida GenericName=Image Viewer Exec=ida %F Terminal=no Categories=Motif;Graphics;Viewer MimeType=image/jpeg;image/tiff;image/png fbi-2.10/color.h0000644000175000017500000000005012506525033011607 0ustar jmmjmmvoid color_init(struct ida_image *img); fbi-2.10/parseconfig.h0000644000175000017500000000471012506525033013000 0ustar jmmjmm/* config options */ struct cfg_option { char *domain; char *section; char *entry; }; struct cfg_cmdline { char letter; char *cmdline; struct cfg_option option; char *value; char *desc; int needsarg:1; int yesno:1; }; void cfg_parse_cmdline(int *argc, char **argv, struct cfg_cmdline *opt); void cfg_help_cmdline(FILE *fp, struct cfg_cmdline *opt, int w1, int w2, int w3); /* file I/O */ int cfg_parse_file(char *dname, char *filename); int cfg_write_file(char *dname, char *filename); /* update */ void cfg_set_str(char *dname, char *sname, char *ename, const char *value); void cfg_set_int(char *dname, char *sname, char *ename, int value); void cfg_set_bool(char *dname, char *sname, char *ename, int value); void cfg_del_section(char *dname, char *sname); void cfg_del_entry(char *dname, char *sname, char *ename); /* search */ char* cfg_sections_first(char *dname); char* cfg_sections_next(char *dname, char *current); char* cfg_sections_prev(char *dname, char *current); char* cfg_sections_index(char *dname, int i); unsigned int cfg_sections_count(char *dname); char* cfg_entries_first(char *dname, char *sname); char* cfg_entries_next(char *dname, char *sname, char *current); char* cfg_entries_prev(char *dname, char *sname, char *current); char* cfg_entries_index(char *dname, char *sname, int i); unsigned int cfg_entries_count(char *dname, char *sname); #define cfg_sections_for_each(dname, item) \ for (item = cfg_sections_first(dname); NULL != item; \ item = cfg_sections_next(dname,item)) char* cfg_search(char *dname, char *sname, char *ename, char *value); /* read */ char* cfg_get_str(char *dname, char *sname, char *ename); unsigned int cfg_get_int(char *dname, char *sname, char *ename, unsigned int def); signed int cfg_get_signed_int(char *dname, char *sname, char *ename, signed int def); float cfg_get_float(char *dname, char *sname, char *ename, float def); int cfg_get_bool(char *dname, char *sname, char *ename, int def); unsigned int cfg_get_sflags(char *dname, char *sname); unsigned int cfg_get_eflags(char *dname, char *sname, char *ename); unsigned int cfg_set_sflags(char *dname, char *sname, unsigned int mask, unsigned int bits); unsigned int cfg_set_eflags(char *dname, char *sname, char *ename, unsigned int mask, unsigned int bits); fbi-2.10/fbiconfig.h0000644000175000017500000000563212506525033012432 0ustar jmmjmm#include "parseconfig.h" #define O_CMDLINE "cmdline", "options" #define O_OPTIONS "config", "options" #define O_HELP O_CMDLINE, "help" #define O_VERSION O_CMDLINE, "version" #define O_WRITECONF O_CMDLINE, "writeconf" #define O_FILE_LIST O_CMDLINE, "file-list" #define O_TEXT_MODE O_CMDLINE, "text-mode" #define O_AUTO_ZOOM O_CMDLINE, "auto-zoom" #define O_AUTO_UP O_OPTIONS, "auto-up" #define O_AUTO_DOWN O_OPTIONS, "auto-down" #define O_FIT_WIDTH O_OPTIONS, "fit-width" #define O_QUIET O_OPTIONS, "quiet" #define O_VERBOSE O_OPTIONS, "verbose" #define O_RANDOM O_OPTIONS, "random" #define O_ONCE O_OPTIONS, "once" #define O_COMMENTS O_OPTIONS, "comments" #define O_EDIT O_OPTIONS, "edit" #define O_BACKUP O_OPTIONS, "backup" #define O_PRESERVE O_OPTIONS, "preserve" #define O_READ_AHEAD O_OPTIONS, "read-ahead" #define O_CACHE_MEM O_OPTIONS, "cache-mem" #define O_BLEND_MSECS O_OPTIONS, "blend-msecs" #define O_VT O_OPTIONS, "vt" #define O_SCROLL O_OPTIONS, "scroll" #define O_TIMEOUT O_OPTIONS, "timeout" #define O_PCD_RES O_OPTIONS, "photocd-res" #define O_GAMMA O_OPTIONS, "gamma" #define O_DEVICE O_OPTIONS, "device" #define O_FONT O_OPTIONS, "font" #define O_VIDEO_MODE O_OPTIONS, "video-mode" #define GET_HELP() cfg_get_bool(O_HELP, 0) #define GET_VERSION() cfg_get_bool(O_VERSION, 0) #define GET_WRITECONF() cfg_get_bool(O_WRITECONF, 0) #define GET_TEXT_MODE() cfg_get_bool(O_TEXT_MODE, 0) #define GET_AUTO_ZOOM() cfg_get_bool(O_AUTO_ZOOM, 0) #define GET_AUTO_UP() cfg_get_bool(O_AUTO_UP, 0) #define GET_AUTO_DOWN() cfg_get_bool(O_AUTO_DOWN, 0) #define GET_FIT_WIDTH() cfg_get_bool(O_FIT_WIDTH, 0) #define GET_QUIET() cfg_get_bool(O_QUIET, 0) #define GET_VERBOSE() cfg_get_bool(O_VERBOSE, 1) #define GET_RANDOM() cfg_get_bool(O_RANDOM, 0) #define GET_ONCE() cfg_get_bool(O_ONCE, 0) #define GET_COMMENTS() cfg_get_bool(O_COMMENTS, 0) #define GET_EDIT() cfg_get_bool(O_EDIT, 0) #define GET_BACKUP() cfg_get_bool(O_BACKUP, 0) #define GET_PRESERVE() cfg_get_bool(O_PRESERVE, 0) #define GET_READ_AHEAD() cfg_get_bool(O_READ_AHEAD, 0) #define GET_CACHE_MEM() cfg_get_int(O_CACHE_MEM, 256) #define GET_BLEND_MSECS() cfg_get_int(O_BLEND_MSECS, 0) #define GET_VT() cfg_get_int(O_VT, 0) #define GET_SCROLL() cfg_get_int(O_SCROLL, 50) #define GET_TIMEOUT() cfg_get_int(O_TIMEOUT, 0) #define GET_PCD_RES() cfg_get_int(O_PCD_RES, 3) #define GET_GAMMA() cfg_get_float(O_GAMMA, 1) /* -------------------------------------------------------------------------- */ extern struct cfg_cmdline fbi_cmd[]; extern struct cfg_cmdline fbi_cfg[]; void fbi_read_config(void); void fbi_write_config(void); fbi-2.10/hex.h0000644000175000017500000000004212506525033011256 0ustar jmmjmmvoid hex_display(char *filename); fbi-2.10/COPYING0000644000175000017500000004307612506525033011372 0ustar jmmjmm GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 675 Mass Ave, Cambridge, MA 02139, USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS Appendix: How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 19yy 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., 675 Mass Ave, Cambridge, MA 02139, USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) 19yy name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. fbi-2.10/.cvsignore0000644000175000017500000000007312506525033012325 0ustar jmmjmmIda.ad.h Make.config exiftran fbi ida logo.h thumbnail.cgi fbi-2.10/parseconfig.c0000644000175000017500000005013312506525033012773 0ustar jmmjmm/* * config file parser * */ #include "config.h" #include #include #include #include #include #include #include #include #include "list.h" #include "misc.h" #include "parseconfig.h" struct cfg_entry { struct list_head next; char *name; unsigned int flags; char *value; }; struct cfg_section { struct list_head next; char *name; unsigned int flags; struct list_head entries; }; struct cfg_domain { struct list_head next; char *name; struct list_head sections; }; LIST_HEAD(domains); /* ------------------------------------------------------------------------ */ /* internal stuff */ static struct cfg_domain *d_last; static struct cfg_section *s_last; static struct cfg_entry *e_last; static struct cfg_domain* cfg_find_domain(char *dname) { struct list_head *item; struct cfg_domain *domain; if (d_last && 0 == strcmp(d_last->name,dname)) return d_last; d_last = NULL; s_last = NULL; e_last = NULL; list_for_each(item,&domains) { domain = list_entry(item, struct cfg_domain, next); if (0 == strcasecmp(domain->name,dname)) { d_last = domain; return domain; } } return NULL; } static struct cfg_domain* cfg_get_domain(char *dname) { struct cfg_domain *domain; domain = cfg_find_domain(dname); if (NULL == domain) { domain = malloc(sizeof(*domain)); memset(domain,0,sizeof(*domain)); domain->name = strdup(dname); INIT_LIST_HEAD(&domain->sections); list_add_tail(&domain->next,&domains); } d_last = domain; return domain; } static struct cfg_section* cfg_find_section(struct cfg_domain *domain, char *sname) { struct list_head *item; struct cfg_section *section; if (s_last && 0 == strcmp(s_last->name,sname)) return s_last; s_last = NULL; e_last = NULL; list_for_each(item,&domain->sections) { section = list_entry(item, struct cfg_section, next); if (0 == strcasecmp(section->name,sname)) { s_last = section; return section; } } return NULL; } static struct cfg_section* cfg_get_section(struct cfg_domain *domain, char *sname) { struct cfg_section *section; section = cfg_find_section(domain,sname); if (NULL == section) { section = malloc(sizeof(*section)); memset(section,0,sizeof(*section)); section->name = strdup(sname); INIT_LIST_HEAD(§ion->entries); list_add_tail(§ion->next,&domain->sections); } s_last = section; return section; } static struct cfg_entry* cfg_find_entry(struct cfg_section *section, char *ename) { struct list_head *item; struct cfg_entry *entry; if (e_last && 0 == strcmp(e_last->name,ename)) return e_last; e_last = NULL; list_for_each(item,§ion->entries) { entry = list_entry(item, struct cfg_entry, next); if (0 == strcasecmp(entry->name,ename)) { e_last = entry; return entry; } } return NULL; } static struct cfg_entry* cfg_get_entry(struct cfg_section *section, char *ename) { struct cfg_entry *entry; entry = cfg_find_entry(section,ename); if (NULL == entry) { entry = malloc(sizeof(*entry)); memset(entry,0,sizeof(*entry)); entry->name = strdup(ename); list_add_tail(&entry->next,§ion->entries); } e_last = entry; return entry; } static void cfg_set_entry(struct cfg_section *section, char *name, const char *value) { struct cfg_entry *entry; entry = cfg_get_entry(section,name); if (entry->value) free(entry->value); entry->value = strdup(value); } static struct cfg_section* cfg_get_sec(char *dname, char *sname) { struct cfg_domain *domain; domain = cfg_find_domain(dname); if (NULL == domain) return NULL; return cfg_find_section(domain,sname); } static struct cfg_entry* cfg_get_ent(char *dname, char *sname, char *ename) { struct cfg_section *section; section = cfg_get_sec(dname,sname); if (NULL == section) return NULL; return cfg_find_entry(section,ename); } /* ------------------------------------------------------------------------ */ /* import / add / del config data */ int cfg_parse_file(char *dname, char *filename) { struct cfg_domain *domain = NULL; struct cfg_section *section = NULL; char line[256],tag[64],value[192]; FILE *fp; int nr; if (NULL == (fp = fopen(filename,"r"))) return -1; nr = 0; domain = cfg_get_domain(dname); while (NULL != fgets(line,255,fp)) { nr++; if (1 == sscanf(line,"# include \"%[^\"]\"",value)) { /* includes */ char *h,*inc; inc = malloc(strlen(filename)+strlen(value)); strcpy(inc,filename); h = strrchr(inc,'/'); if (h) h++; else h = inc; strcpy(h,value); cfg_parse_file(dname,inc); free(inc); continue; } if (line[0] == '\n' || line[0] == '#' || line[0] == '%') continue; if (1 == sscanf(line,"[%99[^]]]",value)) { /* [section] */ section = cfg_get_section(domain,value); } else if (2 == sscanf(line," %63[^= ] = %191[^\n]",tag,value)) { /* foo = bar */ if (NULL == section) { fprintf(stderr,"%s:%d: error: no section\n",filename,nr); } else { char *c = value + strlen(value)-1; while (c > value && (*c == ' ' || *c == '\t')) *(c--) = 0; cfg_set_entry(section,tag,value); } } else { /* Huh ? */ fprintf(stderr,"%s:%d: syntax error\n",filename,nr); } } fclose(fp); return 0; } void cfg_set_str(char *dname, char *sname, char *ename, const char *value) { struct cfg_domain *domain = NULL; struct cfg_section *section = NULL; if (NULL == value) { cfg_del_entry(dname, sname, ename); } else { domain = cfg_get_domain(dname); section = cfg_get_section(domain,sname); cfg_set_entry(section,ename,value); } } void cfg_set_int(char *dname, char *sname, char *ename, int value) { char str[32]; snprintf(str,sizeof(str),"%d",value); cfg_set_str(dname,sname,ename,str); } void cfg_set_bool(char *dname, char *sname, char *ename, int value) { cfg_set_str(dname,sname,ename, value ? "true" : "false"); } void cfg_del_section(char *dname, char *sname) { struct cfg_section *section; struct cfg_entry *entry; section= cfg_get_sec(dname,sname); if (!section) return; list_del(§ion->next); while (!list_empty(§ion->entries)) { entry = list_entry(section->entries.next, struct cfg_entry, next); list_del(&entry->next); free(entry->name); free(entry->value); free(entry); } s_last = NULL; e_last = NULL; free(section->name); free(section); } void cfg_del_entry(char *dname, char *sname, char *ename) { struct cfg_entry *entry; entry = cfg_get_ent(dname,sname,ename); if (!entry) return; e_last = NULL; list_del(&entry->next); free(entry->name); free(entry->value); free(entry); } void cfg_parse_cmdline(int *argc, char **argv, struct cfg_cmdline *opt) { int i,j,o,shift,len; char sopt,*lopt; for (i = 1; i < *argc;) { if (argv[i][0] != '-') { i++; continue; } if (argv[i][1] == 0) { i++; continue; } sopt = 0; lopt = NULL; if (argv[i][1] != '-' && argv[i][2] == 0) { /* short option: -f */ sopt = argv[i][1]; } if (argv[i][1] != '-') { /* long option: -foo */ lopt = argv[i]+1; } else { /* also accept gnu-style: --foo */ lopt = argv[i]+2; } for (shift = 0, o = 0; 0 == shift && opt[o].cmdline != NULL; o++) { len = strlen(opt[o].cmdline); if (opt[o].yesno && sopt && sopt == opt[o].letter) { /* yesno: -f */ cfg_set_bool(opt[o].option.domain, opt[o].option.section, opt[o].option.entry, 1); shift = 1; } else if (opt[o].needsarg && sopt && sopt == opt[o].letter && i+1 < *argc) { /* arg: -f bar */ cfg_set_str(opt[o].option.domain, opt[o].option.section, opt[o].option.entry, argv[i+1]); shift = 2; } else if (opt[o].value && sopt && sopt == opt[o].letter) { /* -f sets fixed value */ cfg_set_str(opt[o].option.domain, opt[o].option.section, opt[o].option.entry, opt[o].value); shift = 1; } else if (opt[o].yesno && lopt && 0 == strcmp(lopt,opt[o].cmdline)) { /* yesno: -foo */ cfg_set_bool(opt[o].option.domain, opt[o].option.section, opt[o].option.entry, 1); shift = 1; } else if (opt[o].yesno && lopt && 0 == strncmp(lopt,"no",2) && 0 == strcmp(lopt+2,opt[o].cmdline)) { /* yesno: -nofoo */ cfg_set_bool(opt[o].option.domain, opt[o].option.section, opt[o].option.entry, 0); shift = 1; } else if (opt[o].needsarg && lopt && 0 == strcmp(lopt,opt[o].cmdline) && i+1 < *argc) { /* arg: -foo bar */ cfg_set_str(opt[o].option.domain, opt[o].option.section, opt[o].option.entry, argv[i+1]); shift = 2; } else if (opt[o].needsarg && lopt && 0 == strncmp(lopt,opt[o].cmdline,len) && 0 == strncmp(lopt+len,"=",1)) { /* arg: -foo=bar */ cfg_set_str(opt[o].option.domain, opt[o].option.section, opt[o].option.entry, argv[i]+2+len); shift = 1; } else if (opt[o].value && lopt && 0 == strcmp(lopt,opt[o].cmdline)) { /* -foo sets some fixed value */ cfg_set_str(opt[o].option.domain, opt[o].option.section, opt[o].option.entry, opt[o].value); shift = 1; } } if (shift) { /* remove processed args */ for (j = i; j < *argc+1-shift; j++) argv[j] = argv[j+shift]; (*argc) -= shift; } else i++; } } void cfg_help_cmdline(FILE *fp, struct cfg_cmdline *opt, int w1, int w2, int w3) { char *val; int o,len; for (o = 0; opt[o].cmdline != NULL; o++) { fprintf(fp,"%*s",w1,""); if (opt[o].letter) { fprintf(fp,"-%c ",opt[o].letter); } else { fprintf(fp," "); } if (opt[o].yesno) { len = fprintf(fp,"-(no)%s ",opt[o].cmdline); } else if (opt[o].needsarg) { len = fprintf(fp,"-%s ",opt[o].cmdline); } else { len = fprintf(fp,"-%s ",opt[o].cmdline); } if (len < w2) fprintf(fp,"%*s",w2-len,""); len = fprintf(fp,"%s ",opt[o].desc); if (w3) { if (len < w3) fprintf(fp,"%*s",w3-len,""); val = cfg_get_str(opt[o].option.domain, opt[o].option.section, opt[o].option.entry); if (val) fprintf(fp,"[%s]",val); } fprintf(fp,"\n"); } } /* ------------------------------------------------------------------------ */ /* export config data */ static int cfg_mkdir(char *filename) { char *h; int rc; h = strrchr(filename,'/'); if (!h || h == filename) return -1; *h = '\0'; rc = mkdir(filename,0777); if (-1 == rc && ENOENT == errno) { cfg_mkdir(filename); rc = mkdir(filename,0777); } if (-1 == rc) fprintf(stderr,"mkdir(%s): %s\n",filename,strerror(errno)); *h = '/'; return rc; } int cfg_write_file(char *dname, char *filename) { struct list_head *item1,*item2; struct cfg_domain *domain; struct cfg_section *section; struct cfg_entry *entry; char *bfile, *tfile; int len; FILE *fp; len = strlen(filename)+10; bfile = malloc(len); tfile = malloc(len); sprintf(bfile,"%s~",filename); sprintf(tfile,"%s.$$$",filename); fp = fopen(tfile,"w"); if (NULL == fp && ENOENT == errno) { cfg_mkdir(tfile); fp = fopen(tfile,"w"); } if (NULL == fp) { fprintf(stderr,"open(%s): %s\n",tfile,strerror(errno)); return -1; } domain = cfg_find_domain(dname); if (NULL != domain) { list_for_each(item1,&domain->sections) { section = list_entry(item1, struct cfg_section, next); fprintf(fp,"[%s]\n",section->name); list_for_each(item2,§ion->entries) { entry = list_entry(item2, struct cfg_entry, next); fprintf(fp,"%s = %s\n",entry->name,entry->value); } fprintf(fp,"\n"); } } fclose(fp); if (-1 == unlink(bfile) && ENOENT != errno) { fprintf(stderr,"unlink(%s): %s\n",bfile,strerror(errno)); return -1; } if (-1 == rename(filename,bfile) && ENOENT != errno) { fprintf(stderr,"rename(%s,%s): %s\n",filename,bfile,strerror(errno)); return -1; } if (-1 == rename(tfile,filename)) { fprintf(stderr,"rename(%s,%s): %s\n",tfile,filename,strerror(errno)); return -1; } return 0; } /* ------------------------------------------------------------------------ */ /* list / search config data */ char* cfg_sections_first(char *dname) { struct list_head *item; struct cfg_domain *domain; struct cfg_section *section; domain = cfg_find_domain(dname); if (NULL == domain) return NULL; item = &domain->sections; if (item->next == &domain->sections) return NULL; section = list_entry(item->next, struct cfg_section, next); s_last = section; e_last = NULL; return section->name; } char* cfg_sections_next(char *dname, char *current) { struct list_head *item; struct cfg_domain *domain; struct cfg_section *section; domain = cfg_find_domain(dname); if (NULL == domain) return NULL; section = cfg_find_section(domain,current); if (NULL == section) return NULL; item = §ion->next; if (item->next == &domain->sections) return NULL; section = list_entry(item->next, struct cfg_section, next); s_last = section; e_last = NULL; return section->name; } char* cfg_sections_prev(char *dname, char *current) { struct list_head *item; struct cfg_domain *domain; struct cfg_section *section; domain = cfg_find_domain(dname); if (NULL == domain) return NULL; section = cfg_find_section(domain,current); if (NULL == section) return NULL; item = §ion->next; if (item->prev == &domain->sections) return NULL; section = list_entry(item->prev, struct cfg_section, next); s_last = section; e_last = NULL; return section->name; } unsigned int cfg_sections_count(char *dname) { struct list_head *item; struct cfg_domain *domain; int count = 0; domain = cfg_find_domain(dname); if (NULL != domain) list_for_each(item,&domain->sections) count++; return count; } char* cfg_sections_index(char *dname, int i) { struct list_head *item; struct cfg_domain *domain; struct cfg_section *section; int count = 0; domain = cfg_find_domain(dname); if (NULL == domain) return NULL; list_for_each(item,&domain->sections) { if (i == count) { section = list_entry(item, struct cfg_section, next); s_last = section; e_last = NULL; return section->name; } count++; } return NULL; } char* cfg_entries_first(char *dname, char *sname) { struct list_head *item; struct cfg_section *section; struct cfg_entry *entry; section = cfg_get_sec(dname,sname); if (NULL == section) return NULL; item = §ion->entries; if (item->next == §ion->entries) return NULL; entry = list_entry(item->next, struct cfg_entry, next); e_last = entry; return entry->name; } char* cfg_entries_next(char *dname, char *sname, char *current) { struct list_head *item; struct cfg_section *section; struct cfg_entry *entry; section = cfg_get_sec(dname,sname); if (NULL == section) return NULL; entry = cfg_find_entry(section,current); if (NULL == entry) return NULL; item = &entry->next; if (item->next == §ion->entries) return NULL; entry = list_entry(item->next, struct cfg_entry, next); e_last = entry; return entry->name; } char* cfg_entries_prev(char *dname, char *sname, char *current) { struct list_head *item; struct cfg_section *section; struct cfg_entry *entry; section = cfg_get_sec(dname,sname); if (NULL == section) return NULL; entry = cfg_find_entry(section,current); if (NULL == entry) return NULL; item = &entry->next; if (item->prev == §ion->entries) return NULL; entry = list_entry(item->prev, struct cfg_entry, next); e_last = entry; return entry->name; } unsigned int cfg_entries_count(char *dname, char *sname) { struct list_head *item; struct cfg_section *section; int count = 0; section = cfg_get_sec(dname,sname); if (NULL != section) list_for_each(item,§ion->entries) count++; return count; } char* cfg_entries_index(char *dname, char *sname, int i) { struct list_head *item; struct cfg_section *section; struct cfg_entry *entry; int count = 0; section = cfg_get_sec(dname,sname); if (NULL == section) return NULL; list_for_each(item,§ion->entries) { if (i == count) { entry = list_entry(item, struct cfg_entry, next); e_last = entry; return entry->name; } count++; } return NULL; } char* cfg_search(char *dname, char *sname, char *ename, char *value) { struct list_head *item1,*item2; struct cfg_domain *domain; struct cfg_section *section; struct cfg_entry *entry; domain = cfg_find_domain(dname); if (NULL == domain) return NULL; list_for_each(item1,&domain->sections) { section = list_entry(item1, struct cfg_section, next); if (sname && 0 != strcasecmp(section->name,sname)) continue; if (!ename) return section->name; list_for_each(item2,§ion->entries) { entry = list_entry(item2, struct cfg_entry, next); if (0 != strcasecmp(entry->name,ename)) continue; if (0 == strcasecmp(entry->value,value)) return section->name; } } return NULL; } /* ------------------------------------------------------------------------ */ /* get config data */ char* cfg_get_str(char *dname, char *sname, char *ename) { struct cfg_entry *entry; entry = cfg_get_ent(dname, sname, ename); if (NULL == entry) return NULL; return entry->value; } unsigned int cfg_get_int(char *dname, char *sname, char *ename, unsigned int def) { char *val; val = cfg_get_str(dname,sname,ename); if (NULL == val) return def; return atoi(val); } signed int cfg_get_signed_int(char *dname, char *sname, char *ename, signed int def) { char *val; val = cfg_get_str(dname,sname,ename); if (NULL == val) return def; return atoi(val); } float cfg_get_float(char *dname, char *sname, char *ename, float def) { char *val; val = cfg_get_str(dname,sname,ename); if (NULL == val) return def; return atof(val); } int cfg_get_bool(char *dname, char *sname, char *ename, int def) { static char *yes[] = { "true", "yes", "on", "1" }; char *val; int i; int retval = 0; val = cfg_get_str(dname,sname,ename); if (NULL == val) return def; for (i = 0; i < sizeof(yes)/sizeof(yes[0]); i++) if (0 == strcasecmp(val,yes[i])) retval = 1; return retval; } /* ------------------------------------------------------------------------ */ /* get/set flags */ unsigned int cfg_get_sflags(char *dname, char *sname) { struct cfg_section *section; section = cfg_get_sec(dname, sname); if (NULL == section) return 0; return section->flags; } unsigned int cfg_get_eflags(char *dname, char *sname, char *ename) { struct cfg_entry *entry; entry = cfg_get_ent(dname, sname, ename); if (NULL == entry) return 0; return entry->flags; } unsigned int cfg_set_sflags(char *dname, char *sname, unsigned int mask, unsigned int bits) { struct cfg_section *section; section = cfg_get_sec(dname, sname); if (NULL == section) return 0; section->flags &= ~mask; section->flags |= bits; return section->flags; } unsigned int cfg_set_eflags(char *dname, char *sname, char *ename, unsigned int mask, unsigned int bits) { struct cfg_entry *entry; entry = cfg_get_ent(dname, sname, ename); if (NULL == entry) return 0; entry->flags &= ~mask; entry->flags |= bits; return entry->flags; } fbi-2.10/misc.h0000644000175000017500000000042412506525033011431 0ustar jmmjmm/* * misc useful #defines ... */ #include #define container_of(ptr, type, member) ({ \ const typeof( ((type *)0)->member ) *__mptr = (ptr); \ (type *)( (char *)__mptr - offsetof(type,member) );}) #define array_size(x) (sizeof(x)/sizeof(x[0])) fbi-2.10/INSTALL0000644000175000017500000000335112506525033011360 0ustar jmmjmm howto compile and install this package ====================================== really short install instructions --------------------------------- $ make $ su -c "make install" the more detailed version ------------------------- Make sure you use GNU make. The file name "GNUmakefile" isn't a joke, this package really requires GNU make. As first step make will do some config checks on your system and write the results to Make.config. If you want to have a look at Make.config before the actual build starts you can run this step separately using "make config". The Makefiles use the usual GNU-ish Makefile conventions for variable names and default values, i.e. prefix=/usr/local, ... The values for some frequently adapted variables are initialized from the enviroment. Thus you can change the defaults simply by setting environment variables: $ prefix="/usr" $ CFLAGS="-O3 -mcpu=i686" $ export prefix CFLAGS Almost any variable can be overridden on the make command line. It is often used this way to install into some buildroot for packaging ... $ su -c "make DESTDIR=/tmp/buildroot install" ... but it works for most other variables equally well. There are some exceptions through, it usually does _not_ work for CFLAGS for example. Try "make verbose=yes" if you want to see the complete command lines executed by make instead of the short messages (for trouble shooting, because you like this way, for whatever reason ...). This also makes the config checks performed by "make config" more verbose. If you don't trust my Makefiles you can run "make -n install" to see what "make install" would do on your system. It will produce human-readable output (unlike automake ...). Have fun, Gerd -- Gerd Hoffmann fbi-2.10/exiftran.c0000644000175000017500000001463112506525033012316 0ustar jmmjmm/* * Transform digital camera jpeg images * * (c) 2002-2012 Gerd Hoffmann */ #include #include #include #include #include #include #include #include #include "transupp.h" /* Support routines for jpegtran */ #include "jpegtools.h" #include "genthumbnail.h" /* ---------------------------------------------------------------------- */ static void dump_exif(FILE *out, ExifData *ed) { const char *title, *value; #ifdef HAVE_NEW_EXIF char buffer[256]; #endif ExifEntry *ee; int tag,i; for (i = 0; i < EXIF_IFD_COUNT; i++) { fprintf(out," ifd %s\n", exif_ifd_get_name (i)); for (tag = 0; tag < 0xffff; tag++) { title = exif_tag_get_title(tag); if (!title) continue; ee = exif_content_get_entry (ed->ifd[i], tag); if (NULL == ee) continue; #ifdef HAVE_NEW_EXIF value = exif_entry_get_value(ee, buffer, sizeof(buffer)); #else value = exif_entry_get_value(ee); #endif fprintf(out," 0x%04x %-30s %s\n", tag, title, value); } } if (ed->data && ed->size) fprintf(out," thumbnail\n %d bytes data\n", ed->size); } static int dump_file(FILE *out, char *filename) { ExifData *ed; ed = exif_data_new_from_file (filename); if (NULL == ed) { fprintf(stderr,"%s: no EXIF data\n",filename); return -1; } fprintf(out,"%s\n",filename); dump_exif(out,ed); fprintf(out,"--\n"); exif_data_unref (ed); return 0; } /* ---------------------------------------------------------------------- */ #define THUMB_MAX 65536 static void usage(FILE *fp, char *name) { char *h; if (NULL != (h = strrchr(name, '/'))) name = h+1; fprintf(fp, "usage: %s [ options ] file\n" "\n" "transform options:\n" " -a automatic (using exif orientation tag)\n" " -9 rotate by 90 degrees clockwise\n" " -1 rotate by 180 degrees clockwise\n" " -2 rotate by 270 degrees clockwise\n" " -f mirror image vertically (top / bottom)\n" " -F mirror image horizontally (left to right)\n" " -t transpose (across UL-to-LR corner)\n" " -T transverse (across UR-to-LL corner)\n" "\n" " -nt don't rotate exif thumbnail\n" " -ni don't rotate jpeg image\n" " -no don't update the orientation tag\n" " -np don't pare lost edges\n" "\n" "other options:\n" " -h print this help text\n" " -d dump exif data\n" " -c create/update comment\n" " -g (re)generate thumbnail\n" " -o output file\n" " -i change files inplace\n" " -b create a backup file (with -i)\n" " -p preserve timestamps (with -i)\n" "\n" "-- \n" "(c) 2002-2012 Gerd Hoffmann [SUSE Labs]\n", name); } int main(int argc, char *argv[]) { JXFORM_CODE transform = JXFORM_NONE; unsigned char *comment = NULL; unsigned char *outfile = NULL; unsigned char *thumbnail = NULL; int tsize = 0; int inplace = 0; unsigned int flags = JFLAG_TRANSFORM_IMAGE | JFLAG_TRANSFORM_THUMBNAIL | JFLAG_TRANSFORM_TRIM | JFLAG_UPDATE_ORIENTATION; int dump = 0; int i, c, rc; for (;;) { c = getopt(argc, argv, "hbpid912fFtTagc:o:n:"); if (c == -1) break; switch (c) { case '9': transform = JXFORM_ROT_90; break; case '1': transform = JXFORM_ROT_180; break; case '2': transform = JXFORM_ROT_270; break; case 'f': transform = JXFORM_FLIP_V; break; case 'F': transform = JXFORM_FLIP_H; break; case 't': transform = JXFORM_TRANSPOSE; break; case 'T': transform = JXFORM_TRANSVERSE; break; case 'a': transform = -1; /* automagic */ break; case 'n': /* don't ... */ switch (optarg[0]) { case 't': flags &= ~JFLAG_TRANSFORM_THUMBNAIL; break; case 'i': flags &= ~JFLAG_TRANSFORM_IMAGE; break; case 'o': flags &= ~JFLAG_UPDATE_ORIENTATION; break; case 'p': flags &= ~JFLAG_TRANSFORM_TRIM; break; default: fprintf(stderr,"unknown option -n%c\n",optarg[0]); exit(1); } break; case 'c': flags |= JFLAG_UPDATE_COMMENT; comment = optarg; break; case 'g': flags |= JFLAG_UPDATE_THUMBNAIL; break; case 'o': outfile = optarg; break; case 'd': dump = 1; break; case 'b': flags |= JFLAG_FILE_BACKUP; break; case 'p': flags |= JFLAG_FILE_KEEP_TIME; break; case 'i': inplace = 1; break; case 'h': usage(stdout,argv[0]); exit(0); default: usage(stderr,argv[0]); exit(1); } } /* sanity checks on the arguments */ if (optind == argc) { fprintf(stderr, "no image file specified (try -h for more info)\n"); exit(1); } /* read-only stuff */ if (dump) { rc = 0; for (i = optind; i < argc; i++) { if (0 != dump_file(stdout,argv[i])) rc = 1; } return rc; } /* r/w sanity checks */ if (NULL != outfile && optind+1 > argc) { fprintf(stderr, "when specifying a output file you can process\n" "one file at a time only (try -h for more info).\n"); exit(1); } if (NULL == outfile && 0 == inplace) { fprintf(stderr, "you have to either specify a output file (-o )\n" "or enable in-place editing (-i). Try -h for more info.\n"); exit(1); } if (JXFORM_NONE == transform && !(flags & JFLAG_UPDATE_COMMENT) && !(flags & JFLAG_UPDATE_THUMBNAIL)) { fprintf(stderr, "What do you want to do today? Neither a new comment nor a\n" "transformation operation was specified (try -h for more info).\n"); exit(1); } /* do actual update work */ if (outfile) { if (flags & JFLAG_UPDATE_THUMBNAIL) { thumbnail = malloc(THUMB_MAX); tsize = create_thumbnail(argv[optind],thumbnail,THUMB_MAX); } return jpeg_transform_files(argv[optind], outfile, transform, comment, thumbnail, tsize, flags); } else { rc = 0; for (i = optind; i < argc; i++) { fprintf(stderr,"processing %s\n",argv[i]); if (flags & JFLAG_UPDATE_THUMBNAIL) { thumbnail = malloc(THUMB_MAX); tsize = create_thumbnail(argv[i],thumbnail,THUMB_MAX); } if (0 != jpeg_transform_inplace(argv[i], transform, comment, thumbnail, tsize, flags)) rc = 1; } return rc; } } fbi-2.10/sane.h0000644000175000017500000000003512506525033011422 0ustar jmmjmmvoid sane_menu(Widget menu); fbi-2.10/fbi.man0000644000175000017500000001665012506525033011572 0ustar jmmjmm.TH FBI 1 "(c) 1998-2012 Gerd Hoffmann" "FBI 2.09" "Linux framebuffer imageviewer" \# \# .SH NAME fbi - Linux framebuffer imageviewer \# \# .SH SYNOPSIS \fBfbi\fP [\fIoptions\fP] \fIfile ...\fP \# \# .SH DESCRIPTION .BR Fbi displays the specified file(s) on the linux console using the framebuffer device. \fIPhotoCD\fP, \fIjpeg\fP, \fIppm\fP, \fIgif\fP, \fItiff\fP, \fIxpm\fP, \fIxwd\fP, \fIbmp\fP, \fIpng\fP and \fIwebp\fP formats are supported natively. For other .BR fbi tries to use .BR "ImageMagick" "(1)\'s" .BR "convert" "(1)." \# \# .SH OPTIONS .TP .B -h, --help Print usage info. .TP .B -V, --version Print \fBfbi\fP version number. .TP .B --store Write command line arguments to config file \fI~/.fbirc\fP. .TP .BI "-l" "\ file" ", --list" "\ file" Read image filelist from \fIfile\fP. .TP .B -P, --text Enable textreading mode. In this mode .BR fbi will display large images without vertical offset (default is to center the images). The \fBSPACE\fP command will first try to scroll down and go to the next image only if it is already on the bottom of the page. Useful if the images you are watching are text pages, all you have to do to get the next piece of text is to press space... .TP .B -a, --autozoom Enable autozoom. .BR Fbi will automagically pick a reasonable zoom factor when loading a new image. .TP .B --(no)autoup Like autozoom, but scale up only. .TP .B --(no)autodown Like autozoom, but scale down only. .TP .B --(no)fitwidth Use width only for autoscaling. .TP .B -v, --(no)verbose Be verbose: enable status line on the bottom of the screen (enabled by default). .TP .B -u, --(no)random Randomize the order of the filenames. .TP .B --(no)comments Display comment tags (if present) instead of the filename. Probably only useful if you added reasonable comments yourself (using .BR "wrjpgcom" "(1)" for example), otherwise you likely just find texts pointing to the software which created the image. .TP .B -e, --(no)edit Enable editing commands. .TP .B --(no)backup Create backup files (when editing images). .TP .B -p, --(no)preserve Preserve timestamps (when editing images). .TP .B --(no)readahead Read ahead images into cache. .TP .BI "--cachemem" "\ size" Image cache \fIsize\fP in megabytes (default is 256). .TP .BI "--blend" "\ time" Image blend \fItime\fP in miliseconds. .TP .BI "-T" "\ n" ", --vt" "\ n" Start on virtual console \fIn\fP. .TP .BI "-s" "\ steps" ", --scroll" "\ steps" Set scroll \fIsteps\fP in pixels (default is 50). .TP .BI "-t" "\ sec" ", --timeout" "\ sec" Start a continuous slideshow where each image is loaded at \fIsec\fP second intervals without any keypress. .TP .B -1, --(no)once Don't loop (only use with \fB-t\fP). .TP .BI "-r" "\ n" ", --resolution" "\ n" Select resolution, \fIn = 1..5\fP (default is 3, only \fIPhotoCD\fP). .TP .BI "-g" "\ n" ", --gamma" "\ n" Gamma correction. Requires \fIPseudocolor\fP or \fIDirectcolor\fP visual, doesn't work for \fITruecolor\fP (default is 1). .TP .BI "-f" "\ " ", --font" "\ " Set font. This \fI\fP can be anything fontconfig accepts (see .BR "fonts\-conf" "(5))." Try .BR "fc\-list" "(1)" for a list of known fonts on your system. The fontconfig config file is evaluated as well, so any generic stuff defined there (such as mono, sans) will work as well. It is recommended to use monospaced fonts, the textboxes (help text, exif info) look better then. .TP .BI "-d" "\ /dev/fbN" ", --device" "\ /dev/fbN" Use \fI/dev/fbN\fP device framebuffer. Default is the one your virtual console is mapped to. .TP .BI "-m" "\ videomode" ", --mode" "\ videomode" Name of the video mode to use (video mode must be listed in \fI/etc/fb.modes\fP). Default is not to change the video mode. \# \# .SH ENVIRONMENT .BR Fbi uses the following environment variables: .TP .BR FBGAMMA This variable may be used to specify a default gamma correction. \# \# .SH "COMMAND USAGE" The commands take effect immediately; it is not necessary to type a carriage return. .PP In the following commands, \fIi\fP is a numerical argument. .SS Scrolling .TP \fBLEFT_ARROW\fP, \fBRIGHT_ARROW\fP, \fBUP_ARROW\fP, \fBDOWN_ARROW\fP Scroll large images. .TP \fBPREV_SCREEN\fP, \fBk\fP Previous image. .TP \fBNEXT_SCREEN\fP, \fBSPACE\fP, \fBj\fP Next image. .TP \fIi\fP\fBg\fP Jump to image #\fIi\fP. .TP \fBRETURN\fP Write the filename of the current image to .BR "stdout" "(3)," then go to the next image. .P The \fBRETURN\fP vs. \fBSPACE\fP key thing can be used to create a file list while reviewing the images and use the list for batch processing later on: .P .in +4n \fIfbi\ file1.gif\ file2.jpg\ file3.jpg >\ fileimagelist.lst\fP .in .P .in +4n some \fBRETURN\fP and \fBSPACE\fP... .P .in +4n \fIfbi\ -l\ fileimagelist.lst\fP .in .SS Zoom .TP \fBa\fP Autozoom. .TP \fB+\fP In. .TP \fB-\fP Out. .TP \fIi\fP\fBs\fP Set zoom to \fIi\fP%. .SS Other .TP \fBESQ\fP, \fBq\fP Quit. .TP \fBv\fP Toggle status line. .TP \fBh\fP Display textbox with brief help. .TP \fBi\fP Display textbox with some \fIEXIF\fP info. .TP \fBp\fP Pause the slideshow (if started with \fB-t\fP, toggle). .SS Edit mode .BR Fbi also provides some very basic image editing facilities. You have to start .BR fbi with the \fI-e\fP switch to use them. .TP \fBD\fP, \fBShift+d\fP Delete image. .TP \fBr\fP Rotate 90 degrees clockwise. .TP \fBl\fP Rotate 90 degrees counter-clock wise. .TP \fBx\fP Mirror image vertically (top / bottom). .TP \fBy\fP Mirror image horizontally (left to right). .P The delete function actually wants a capital letter \fBD\fP, thus you have to type \fBShift+d\fP. This is done to avoid deleting images by mistake because there are no safety bells: If you ask .BR fbi to delete the image, it will be deleted without questions asked. .P The rotate function actually works for \fIJPEG\fP images only. It does a lossless transformation of the image. \# \# .SH BUGS .BR Fbi needs rw access to the framebuffer devices (\fI/dev/fbN\fP), i.e you (our your admin) have to make sure .BR fbi can open the devices in rw mode. The IMHO most elegant way is to use .BR PAM (7) to chown the devices to the user logged in on the console. Another way is to create some group, chown the special files to that group and put the users which are allowed to use the framebuffer device into the group. You can also make the special files world writable, but be aware of the security implications this has. On a private box it might be fine to handle it this way though. .P .BR Fbi also needs access to the linux console (\fI/dev/ttyN\fP) for sane console switch handling. That is obviously no problem for console logins, but any kind of a pseudo tty (xterm, ssh, screen, ...) will \fBnot\fP work. \# \# .SH "SEE ALSO" .BR convert (1), .BR fbset (1), .BR fc-list (1), .BR imagemagick (1), .BR wrjpgcom (1), .BR fonts-conf (5), .BR PAM (7) \# \# .SH AUTHOR Gerd Hoffmann .BR \# \# .SH COPYRIGHT Copyright (c) 1999-2012 Gerd Hoffmann .P 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. .P 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. .P 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., 675 Mass Ave, Cambridge, MA 02139, USA. fbi-2.10/exiftran.man.fr0000644000175000017500000001064712506525033013260 0ustar jmmjmm.TH EXIFTRAN 1 "(c) 2002-2012 Gerd Hoffmann" "EXIFTRAN 2.09" "Transformation d'images jpeg d'appareil photo numérique" \# \# .SH NOM exiftran - transformation d'images jpeg d'appareil photo numérique \# \# .SH SYNOPSIS .TP \fBexiftran\fP [\fIoptions\fP] \fIfile1 file2 ... fileN\fP .TP \fBexiftran\fP -i [\fItransformation options\fP] [\fIautres options\fP] \fIfile1 file2 ... fileN\fP .TP \fBexiftran\fP -o \fIfichiersortie\fP [\fItransformation options\fP] [\fIautres options\fP] \fIfichierentree\fP .TP \fBexiftran\fP -d \fIfile1 file2 ... fileN\fP > \fIexifinfo\fP \# \# .SH DESCRIPTION .BR Exiftran est un utilitaire en ligne de commande pour transformer des images \fIjpeg\fP d'appareil photo numérique. Il peut faire des rotations sans perte de données comme .BR "jpegtran" "(1)," mais au contraire de .BR "jpegtran" "(1)" il tient compte des données \fIEXIF\fP : il peut pivoter les images automatiquement en vérifiant la propriété exif d'orientation ; il met à jour les informations exif si nécessaire (dimension de l'image, orientation) ; il pivote aussi la miniature exif. Il peut traiter plusieurs images en une seule opération. \# \# .SH "OPTIONS DE TRANSFORMATION" .TP .B -a Automatique (utilise la propriété d'orientation exif). .TP .B -9 Rotation de 90 degrés dans le sens des aiguilles d'une montre. .TP .B -1 Rotation de 180 degrés dans le sens des aiguilles d'une montre. .TP .B -2 Rotation de 270 degrés dans le sens des aiguilles d'une montre. .TP .B -f Rotation d'axe horizontal (haut / bas). .TP .B -F Rotation d'axe vertical (gauche / droite). .TP .B -t Rotation d'axe oblique (sommets HG et BD). .TP .B -T Rotation d'axe oblique (sommets HD et BG). .TP .B -nt Ne pas transformer la miniature exif. .TP .B -ni Ne pas transformer l'image jpeg. Vous pourriez avoir besoin de ceci ou de l'option \fB-nt\fP pour faire des corrections dans le cas où vous avez transformé une image avec des utilitaires qui ignorent la miniature exif. Mettre à jour la miniature seule avec \fB-g\fP est une autre solution. .TP .B -no Ne pas mettre à jour la propriété d'orientation. Par défaut .BR exiftran positionne l'orientation à "1" (aucune transformation nécessaire) pour empêcher d'autres logiciels de manipulation des données exif d'essayer de pivoter l'image qui l'est déjà. .TP .B -np Ne pas couper les bordures perdus. Par défaut .BR exiftran ne préserve pas la dimension des images qui ne respectent pas un multiple de 8 pixels. Il préfère couper une bande de quelques pixels plutôt que d'offrir une image détériorée. Utilisez cette options si vous les voulez tout de même. \# \# .SH "AUTRES OPTIONS" .TP .B -h Afficher un court message d'aide. .TP .B -d Extraire les données exif du ou des fichiers. .TP .BI "-c" "\ texte" Enregistrer un \fItexte\fP dans la propriété commentaire. .TP .B -g Refabriquer la miniature exif. .TP .BI "-o" "\ fichier" Indiquer le \fIfichier\fP de sortie. Ce mode n'autorise qu'un seul fichier en entrée. .TP .B -i Activer la modification directe des images. .BR Exiftran accepte plusieurs fichiers en entrée. Vous devez indiquer cette option ou un fichier de sortie avec \fB-o\fP pour toutes les opérations qui modifient l'image (c-à-d toutes sauf \fB-d\fP évidemment). .TP .B -b Créer un fichier de sauvegarde lors des modifications directes (implique \fB-i\fP). .TP .B -p Préserver l'horodatage (atime + mtime) lors des modifications directes (implique \fB-i\fP). \# \# .SH EXEMPLES Rotation automatique de tous les fichiers jpeg du répertoire courant : .P .in +4n \fIexiftran\ -ai\ *.jpeg\fP .in \# \# .SH "VOIR AUSSI" .BR exif (1), .BR exiftags (1), .BR jpegtran (1) \# \# .SH TRADUCTEUR Stéphane Aulery .BR \# \# .SH AUTEUR Gerd Hoffmann .BR \# \# .SH COPYRIGHT Copyright (c) 2002-2012 Gerd Hoffmann .P 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. .P 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. .P 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., 675 Mass Ave, Cambridge, MA 02139, USA. fbi-2.10/genthumbnail.c0000644000175000017500000001203012506525033013142 0ustar jmmjmm#include #include #include #include #include #include #include #include "transupp.h" /* Support routines for jpegtran */ #include "jpegtools.h" #include "misc.h" #include "readers.h" #include "filter.h" #include "genthumbnail.h" /* ---------------------------------------------------------------------- */ static struct ida_image* read_jpeg(char *filename) { struct ida_image *img; FILE *fp; unsigned int y; void *data; /* open file */ if (NULL == (fp = fopen(filename, "r"))) { fprintf(stderr,"open %s: %s\n",filename,strerror(errno)); return NULL; } /* load image */ img = malloc(sizeof(*img)); memset(img,0,sizeof(*img)); data = jpeg_loader.init(fp,filename,0,&img->i,0); if (NULL == data) { fprintf(stderr,"loading %s [%s] FAILED\n",filename,jpeg_loader.name); free(img); return NULL; } img->data = malloc(img->i.width * img->i.height * 3); for (y = 0; y < img->i.height; y++) jpeg_loader.read(img->data + img->i.width * 3 * y, y, data); jpeg_loader.done(data); return img; } /* ---------------------------------------------------------------------- */ static struct ida_image* scale_thumbnail(struct ida_image *src, int max) { struct op_resize_parm p; struct ida_rect rect; struct ida_image *dest; void *data; unsigned int y; float xs,ys,scale; xs = (float)max / src->i.width; ys = (float)max / src->i.height; scale = (xs < ys) ? xs : ys; dest = malloc(sizeof(*dest)); memset(dest,0,sizeof(*dest)); memset(&rect,0,sizeof(rect)); memset(&p,0,sizeof(p)); p.width = src->i.width * scale; p.height = src->i.height * scale; p.dpi = src->i.dpi; if (0 == p.width) p.width = 1; if (0 == p.height) p.height = 1; data = desc_resize.init(src,&rect,&dest->i,&p); dest->data = malloc(dest->i.width * dest->i.height * 3); for (y = 0; y < dest->i.height; y++) desc_resize.work(src,&rect, dest->data + 3 * dest->i.width * y, y, data); desc_resize.done(data); return dest; } /* ---------------------------------------------------------------------- */ struct thc { struct jpeg_compress_struct dst; struct jpeg_error_mgr err; unsigned char *out; int osize; }; static void thc_dest_init(struct jpeg_compress_struct *cinfo) { struct thc *h = container_of(cinfo, struct thc, dst); cinfo->dest->next_output_byte = h->out; cinfo->dest->free_in_buffer = h->osize; } static boolean thc_dest_flush(struct jpeg_compress_struct *cinfo) { fprintf(stderr,"jpeg: panic: output buffer full\n"); exit(1); } static void thc_dest_term(struct jpeg_compress_struct *cinfo) { struct thc *h = container_of(cinfo, struct thc, dst); h->osize -= cinfo->dest->free_in_buffer; } static struct jpeg_destination_mgr thumbnail_dst = { .init_destination = thc_dest_init, .empty_output_buffer = thc_dest_flush, .term_destination = thc_dest_term, }; static int compress_thumbnail(struct ida_image *img, char *dest, int max) { struct thc thc; unsigned char *line; unsigned int i; memset(&thc,0,sizeof(thc)); thc.dst.err = jpeg_std_error(&thc.err); jpeg_create_compress(&thc.dst); thc.dst.dest = &thumbnail_dst; thc.out = dest; thc.osize = max; thc.dst.image_width = img->i.width; thc.dst.image_height = img->i.height; thc.dst.input_components = 3; thc.dst.in_color_space = JCS_RGB; jpeg_set_defaults(&thc.dst); jpeg_start_compress(&thc.dst, TRUE); for (i = 0, line = img->data; i < img->i.height; i++, line += img->i.width*3) jpeg_write_scanlines(&thc.dst, &line, 1); jpeg_finish_compress(&(thc.dst)); jpeg_destroy_compress(&(thc.dst)); return thc.osize; } /* ---------------------------------------------------------------------- */ int create_thumbnail(char *filename, unsigned char *dest, int max) { struct ida_image *img,*thumb; int size; //fprintf(stderr,"%s: read ",filename); img = read_jpeg(filename); if (!img) { fprintf(stderr,"FAILED\n"); return -1; } //fprintf(stderr,"scale "); thumb = scale_thumbnail(img,160); if (!thumb) { free(img->data); free(img); fprintf(stderr,"FAILED\n"); return -1; } //fprintf(stderr,"compress "); size = compress_thumbnail(thumb,dest,max); /* cleanup */ free(img->data); free(img); free(thumb->data); free(thumb); return size; } /* ---------------------------------------------------------------------- */ #if 0 #define THUMB_MAX 65536 static int handle_image(char *filename) { char *dest; int size; dest = malloc(THUMB_MAX); size = create_thumbnail(filename,dest,THUMB_MAX); fprintf(stderr,"transform "); jpeg_transform_inplace(filename, JXFORM_NONE, NULL, dest, size, JFLAG_UPDATE_THUMBNAIL); fprintf(stderr,"done\n"); return 0; } int main(int argc, char *argv[]) { int i; for (i = 1; i < argc; i++) handle_image(argv[i]); return 0; } #endif fbi-2.10/color.c0000644000175000017500000003436212506525033011617 0ustar jmmjmm#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "RegEdit.h" #include "ida.h" #include "x11.h" #include "readers.h" #include "viewer.h" #include "color.h" #include "lut.h" /* ---------------------------------------------------------------------- */ #define HIST_SIZE 60 struct ida_coledit; struct ida_hist { /* x11 */ GC gc; unsigned long color; /* histogram */ Widget hist; unsigned int max; unsigned int data[256]; /* mapping */ Widget map; struct op_map_parm_ch parm; struct ida_coledit *up; }; struct ida_coledit { /* misc */ Widget dlg,form,vals,toggle; Widget l,r,t,b,g; int lock,apply; /* histogram data */ struct ida_hist red; struct ida_hist green; struct ida_hist blue; struct ida_hist *cur; }; /* ---------------------------------------------------------------------- */ static void color_calchist(struct ida_image *img, struct ida_coledit *me) { unsigned char *pix; unsigned int i,x,y,max; pix = img->data; for (y = 0; y < img->i.height; y++) { for (x = 0; x < img->i.width; x++) { me->red.data[pix[0]]++; me->green.data[pix[1]]++; me->blue.data[pix[2]]++; pix += 3; } } max = 0; for (i = 0; i < 256; i++) { if (max < me->red.data[i]) max = me->red.data[i]; if (max < me->green.data[i]) max = me->green.data[i]; if (max < me->blue.data[i]) max = me->blue.data[i]; } me->red.max = max; me->green.max = max; me->blue.max = max; } static void color_update(struct ida_coledit *me, struct ida_hist *h, int text) { struct op_map_parm param; char tmp[32]; if (me->lock) { if (&me->red != h) me->red.parm = h->parm; if (&me->green != h) me->green.parm = h->parm; if (&me->blue != h) me->blue.parm = h->parm; XClearArea(XtDisplay(me->red.hist), XtWindow(me->red.hist), 0,0,0,0, True); XClearArea(XtDisplay(me->red.map), XtWindow(me->red.map), 0,0,0,0, True); XClearArea(XtDisplay(me->green.hist), XtWindow(me->green.hist), 0,0,0,0, True); XClearArea(XtDisplay(me->green.map), XtWindow(me->green.map), 0,0,0,0, True); XClearArea(XtDisplay(me->blue.hist), XtWindow(me->blue.hist), 0,0,0,0, True); XClearArea(XtDisplay(me->blue.map), XtWindow(me->blue.map), 0,0,0,0, True); } else { XClearArea(XtDisplay(h->hist), XtWindow(h->hist), 0,0,0,0, True); XClearArea(XtDisplay(h->map), XtWindow(h->map), 0,0,0,0, True); } if ((me->lock || h == me->cur) && text >= 1) { /* mouse-click updateable values */ sprintf(tmp,"%d",h->parm.left); XmTextSetString(me->l,tmp); sprintf(tmp,"%d",h->parm.right); XmTextSetString(me->r,tmp); } if ((me->lock || h == me->cur) && text >= 2) { /* others */ sprintf(tmp,"%d",h->parm.bottom); XmTextSetString(me->b,tmp); sprintf(tmp,"%d",h->parm.top); XmTextSetString(me->t,tmp); sprintf(tmp,"%.2f",h->parm.gamma); XmTextSetString(me->g,tmp); } param.red = me->red.parm; param.green = me->green.parm; param.blue = me->blue.parm; viewer_start_preview(ida,&desc_map,¶m); } static void color_drawmap(Widget widget, XtPointer client_data, XtPointer calldata) { struct ida_hist *me = client_data; XmDrawingAreaCallbackStruct *cb = calldata; XGCValues values; int left,right,top,bottom,i,val,x1,y1,x2,y2; float p; if (cb->reason == XmCR_EXPOSE) { /* window needs redraw */ XExposeEvent *e = (XExposeEvent*)cb->event; if (e->count) return; values.foreground = x11_gray; XChangeGC(dpy,me->gc,GCForeground,&values); left = me->parm.left * HIST_SIZE / 255; right = me->parm.right * HIST_SIZE / 255; bottom = me->parm.bottom * HIST_SIZE / 255; top = me->parm.top * HIST_SIZE / 255; if (me->parm.left > 0) XFillRectangle(dpy,XtWindow(me->map),me->gc, 0,0,left,HIST_SIZE); if (me->parm.right < 255) XFillRectangle(dpy,XtWindow(me->map),me->gc, right,0,HIST_SIZE-right,HIST_SIZE); values.foreground = me->color; XChangeGC(dpy,me->gc,GCForeground,&values); if (me->parm.left > 0) XDrawLine(dpy,XtWindow(me->map),me->gc, 0,HIST_SIZE-bottom,left,HIST_SIZE-bottom); if (me->parm.right < 255) XDrawLine(dpy,XtWindow(me->map),me->gc, right,HIST_SIZE-top,HIST_SIZE,HIST_SIZE-top); p = 1/me->parm.gamma; x2 = y2 = 0; for (i = left; i <= right; i++) { val = pow((float)(i-left)/(right-left),p) * (top-bottom) + 0.5; val += bottom; if (val < 0) val = 0; if (val > HIST_SIZE) val = HIST_SIZE; x1 = x2; y1 = y2; x2 = i; y2 = HIST_SIZE-val; if (i > left) XDrawLine(dpy,XtWindow(me->map),me->gc, x1,y1,x2,y2); } } } static void color_drawhist(Widget widget, XtPointer client_data, XtPointer calldata) { struct ida_hist *me = client_data; XmDrawingAreaCallbackStruct *cb = calldata; XGCValues values; int i,val; if (cb->reason == XmCR_EXPOSE) { /* window needs redraw */ XExposeEvent *e = (XExposeEvent*)cb->event; if (e->count) return; values.foreground = x11_gray; XChangeGC(dpy,me->gc,GCForeground,&values); if (me->parm.left > 0) XFillRectangle(dpy,XtWindow(me->hist),me->gc, 0,0,me->parm.left,HIST_SIZE); if (me->parm.right < 255) XFillRectangle(dpy,XtWindow(me->hist),me->gc, me->parm.right,0,256-me->parm.right,HIST_SIZE); values.foreground = me->color; XChangeGC(dpy,me->gc,GCForeground,&values); for (i = 0; i < 256; i++) { val = log(me->data[i])*HIST_SIZE/log(me->max); XDrawLine(dpy,XtWindow(me->hist),me->gc, i,HIST_SIZE,i,HIST_SIZE-val); } } } static void color_mouse(Widget widget, XtPointer client_data, XEvent *ev, Boolean *cont) { struct ida_hist *me = client_data; int x; switch (ev->type) { case ButtonPress: case ButtonRelease: { XButtonEvent *e = (XButtonEvent*)ev; x = e->x; break; } case MotionNotify: { XMotionEvent *e = (XMotionEvent*)ev; x = e->x; break; default: return; } } if (x > (me->parm.right + me->parm.left)/2) { me->parm.right = x; if (me->parm.right > 255) me->parm.right = 255; if (me->parm.right < me->parm.left) me->parm.right = me->parm.left; } else { me->parm.left = x; if (me->parm.left < 0) me->parm.left = 0; if (me->parm.left > me->parm.right) me->parm.left = me->parm.right; } color_update(me->up,me,1); } static void color_lock(Widget widget, XtPointer client_data, XtPointer calldata) { struct ida_coledit *me = client_data; XmToggleButtonCallbackStruct *cb = calldata; Widget label,button; label = XmOptionLabelGadget(me->vals); button = XmOptionButtonGadget(me->vals); me->lock = cb->set; XtVaSetValues(label,XtNsensitive,!me->lock,NULL); XtVaSetValues(button,XtNsensitive,!me->lock,NULL); } static void color_vals(Widget widget, XtPointer client_data, XtPointer calldata) { struct ida_hist *cur = client_data; struct ida_coledit *me = cur->up; me->cur = cur; color_update(me,cur,2); } static void color_text(Widget widget, XtPointer client_data, XtPointer calldata) { struct ida_coledit *me = client_data; int left,right,bottom,top; float gamma; if (widget == me->l && 1 == sscanf(XmTextGetString(me->l),"%d",&left) && left >= 0 && left <= me->cur->parm.right) { me->cur->parm.left = left; } if (widget == me->r && 1 == sscanf(XmTextGetString(me->r),"%d",&right) && me->cur->parm.left <= right && right <= 255) { me->cur->parm.right = right; } if (widget == me->b && 1 == sscanf(XmTextGetString(me->b),"%d",&bottom) && bottom <= me->cur->parm.top) { me->cur->parm.bottom = bottom; } if (widget == me->t && 1 == sscanf(XmTextGetString(me->t),"%d",&top) && me->cur->parm.bottom <= top) { me->cur->parm.top = top; } if (widget == me->g && 1 == sscanf(XmTextGetString(me->g),"%f",&gamma)) { me->cur->parm.gamma = gamma; } color_update(me,me->cur,0); } static void color_pick_ok(int x, int y, unsigned char *pix, XtPointer data) { struct ida_coledit *me = data; int max; if (debug) fprintf(stderr,"color_pick_ok: +%d+%d %d/%d/%d\n", x,y, pix[0],pix[1],pix[2]); max = 0; if (max < pix[0]) max = pix[0]; if (max < pix[1]) max = pix[1]; if (max < pix[2]) max = pix[2]; XmToggleButtonSetState(me->toggle,False,True); me->red.parm.right = (int)255 * pix[0] / max; color_update(me,&me->red,1); me->green.parm.right = (int)255 * pix[1] / max; color_update(me,&me->green,1); me->blue.parm.right = (int)255 * pix[2] / max; color_update(me,&me->blue,1); if (debug) fprintf(stderr,"color_pick_ok: %d/%d/%d max=%d\n", me->red.parm.right, me->green.parm.right, me->blue.parm.right, max); } static void color_pick(Widget widget, XtPointer client_data, XtPointer calldata) { struct ida_coledit *me = client_data; viewer_pick(ida,color_pick_ok,me); } static void color_createhist(Widget parent, char *name, unsigned long color, struct ida_hist *me) { char tmp[32]; sprintf(tmp,"h%s",name); me->hist = XtVaCreateManagedWidget(tmp,xmDrawingAreaWidgetClass,parent, XtNwidth,256, XtNheight,HIST_SIZE, NULL); sprintf(tmp,"m%s",name); me->map = XtVaCreateManagedWidget(tmp,xmDrawingAreaWidgetClass,parent, XtNwidth,HIST_SIZE, XtNheight,HIST_SIZE, NULL); XtAddEventHandler(me->hist, ButtonPressMask | ButtonReleaseMask | ButtonMotionMask, False,color_mouse,me); XtAddCallback(me->hist,XmNexposeCallback,color_drawhist,me); XtAddCallback(me->map,XmNexposeCallback,color_drawmap,me); me->gc = XCreateGC(dpy,XtWindow(app_shell),0,NULL); me->color = color; me->parm = op_map_nothing; } static void color_button_cb(Widget widget, XtPointer client_data, XtPointer calldata) { struct ida_coledit *me = client_data; XmSelectionBoxCallbackStruct *cb = calldata; if (cb->reason == XmCR_OK) me->apply = 1; XtDestroyWidget(XtParent(me->form)); } static void color_destroy(Widget widget, XtPointer client_data, XtPointer calldata) { struct ida_coledit *me = client_data; struct op_map_parm param; if (me->apply) { param.red = me->red.parm; param.green = me->green.parm; param.blue = me->blue.parm; viewer_start_op(ida,&desc_map,¶m); } else viewer_cancel_preview(ida); viewer_unpick(ida); free(me); } void color_init(struct ida_image *img) { Widget menu,push,rc; struct ida_coledit *me; Arg args[2]; me = malloc(sizeof(*me)); memset(me,0,sizeof(*me)); color_calchist(img,me); /* dialog shell */ me->dlg = XmCreatePromptDialog(app_shell,"color",NULL,0); XmdRegisterEditres(XtParent(me->dlg)); XtUnmanageChild(XmSelectionBoxGetChild(me->dlg,XmDIALOG_SELECTION_LABEL)); XtUnmanageChild(XmSelectionBoxGetChild(me->dlg,XmDIALOG_HELP_BUTTON)); XtUnmanageChild(XmSelectionBoxGetChild(me->dlg,XmDIALOG_TEXT)); me->form = XtVaCreateManagedWidget("form",xmFormWidgetClass, me->dlg,NULL); XtAddCallback(XtParent(me->dlg),XmNdestroyCallback,color_destroy,me); XtAddCallback(me->dlg,XmNokCallback,color_button_cb,me); XtAddCallback(me->dlg,XmNcancelCallback,color_button_cb,me); /* histograms */ XtVaCreateManagedWidget("hist",xmLabelWidgetClass, me->form,NULL); color_createhist(me->form,"red", x11_red, &me->red); color_createhist(me->form,"green",x11_green,&me->green); color_createhist(me->form,"blue", x11_blue, &me->blue); me->red.up = me; me->green.up = me; me->blue.up = me; XtVaCreateManagedWidget("map",xmLabelWidgetClass, me->form,NULL); /* control */ me->toggle = XtVaCreateManagedWidget("lock",xmToggleButtonWidgetClass, me->form,NULL); XtAddCallback(me->toggle,XmNvalueChangedCallback,color_lock,me); menu = XmCreatePulldownMenu(me->form,"valsM",NULL,0); XtSetArg(args[0],XmNsubMenuId,menu); me->vals = XmCreateOptionMenu(me->form,"vals",args,1); XtManageChild(me->vals); push = XtVaCreateManagedWidget("red",xmPushButtonWidgetClass,menu,NULL); XtAddCallback(push,XmNactivateCallback,color_vals,&me->red); push = XtVaCreateManagedWidget("green",xmPushButtonWidgetClass,menu,NULL); XtAddCallback(push,XmNactivateCallback,color_vals,&me->green); push = XtVaCreateManagedWidget("blue",xmPushButtonWidgetClass,menu,NULL); XtAddCallback(push,XmNactivateCallback,color_vals,&me->blue); /* in range */ rc = XtVaCreateManagedWidget("in",xmRowColumnWidgetClass,me->form,NULL); XtVaCreateManagedWidget("label",xmLabelWidgetClass,rc,NULL); me->l = XtVaCreateManagedWidget("left",xmTextWidgetClass,rc,NULL); XtAddCallback(me->l,XmNvalueChangedCallback,color_text,me); me->r = XtVaCreateManagedWidget("right",xmTextWidgetClass,rc,NULL); XtAddCallback(me->r,XmNvalueChangedCallback,color_text,me); /* out range */ rc = XtVaCreateManagedWidget("out",xmRowColumnWidgetClass,me->form,NULL); XtVaCreateManagedWidget("label",xmLabelWidgetClass,rc,NULL); me->b = XtVaCreateManagedWidget("bottom",xmTextWidgetClass,rc,NULL); XtAddCallback(me->b,XmNvalueChangedCallback,color_text,me); me->t = XtVaCreateManagedWidget("top",xmTextWidgetClass,rc,NULL); XtAddCallback(me->t,XmNvalueChangedCallback,color_text,me); /* gamma */ rc = XtVaCreateManagedWidget("gamma",xmRowColumnWidgetClass,me->form,NULL); XtVaCreateManagedWidget("label",xmLabelWidgetClass,rc,NULL); me->g = XtVaCreateManagedWidget("gamma",xmTextWidgetClass,rc,NULL); XtAddCallback(me->g,XmNvalueChangedCallback,color_text,me); /* testing stuff */ rc = XtVaCreateManagedWidget("pick",xmRowColumnWidgetClass,me->form,NULL); push = XtVaCreateManagedWidget("white",xmPushButtonWidgetClass,rc,NULL); XtAddCallback(push,XmNactivateCallback,color_pick,me); XtManageChild(me->dlg); me->cur = &me->red; color_update(me,me->cur,2); XmToggleButtonSetState(me->toggle,True,True); } fbi-2.10/.gitignore0000644000175000017500000000007712506525033012321 0ustar jmmjmmIda.ad.h Make.config exiftran fbi ida logo.h thumbnail.cgi *.o fbi-2.10/browser.c0000644000175000017500000003572512506525033012170 0ustar jmmjmm/* * simple file browser * (c) 2001-03 Gerd Hoffmann * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "RegEdit.h" #include "ida.h" #include "readers.h" #include "viewer.h" #include "browser.h" #include "filter.h" #include "x11.h" #include "dither.h" #include "selections.h" #include "filebutton.h" #include "misc.h" #include "idaconfig.h" #include "desktop.h" /*----------------------------------------------------------------------*/ struct browser_handle; struct browser_handle { char *dirname; char *lastdir; char *filter; Widget shell; Widget scroll; Widget container; Widget status; XmString details[DETAIL_COUNT+1]; struct list_head files; struct list_head *item; unsigned int dirs,sfiles,afiles; XtWorkProcId wproc; }; /*----------------------------------------------------------------------*/ static void dir_info(struct file_button *file) { char path[256]; char comment[256]; int len; snprintf(path,sizeof(path),"%s/.directory",file->filename); len = desktop_read_entry(path, "Comment=", comment, sizeof(comment)); if (len) { XmStringFree(file->details[DETAIL_COMMENT]); file->details[DETAIL_COMMENT] = XmStringGenerate(comment, NULL, XmMULTIBYTE_TEXT,NULL); XtVaSetValues(file->widget, XmNdetail, file->details, XmNdetailCount, DETAIL_COUNT, NULL); } } static Boolean browser_statfiles(XtPointer clientdata) { struct browser_handle *h = clientdata; struct file_button *file; struct list_head *item; char line[80]; XmString str; Pixmap pix; char *type; if (h->item == &h->files) { /* done => read thumbnails now */ h->wproc = 0; list_for_each(item,&h->files) { file = list_entry(item, struct file_button, window); if ((file->st.st_mode & S_IFMT) != S_IFREG) continue; fileinfo_queue(file); } list_for_each(item,&h->files) { file = list_entry(item, struct file_button, window); if ((file->st.st_mode & S_IFMT) != S_IFDIR) continue; dir_info(file); } /* update status line */ if (h->filter) { snprintf(line, sizeof(line), "%u dirs, %u/%u files [%s]", h->dirs,h->sfiles,h->afiles,h->filter); } else { snprintf(line, sizeof(line), "%u dirs, %u files", h->dirs,h->afiles); } str = XmStringGenerate(line, NULL, XmMULTIBYTE_TEXT, NULL); XtVaSetValues(h->status,XmNlabelString,str,NULL); XmStringFree(str); h->item = NULL; return TRUE; } /* handle file */ file = list_entry(h->item, struct file_button, window); switch (file->st.st_mode & S_IFMT) { case S_IFDIR: type = "dir"; break; case S_IFREG: type = "file"; break; default: type = NULL; } if (type) { pix = XmGetPixmap(XtScreen(h->container),type,0,0); file_set_icon(file,pix,pix); } h->item = h->item->next; return FALSE; } static void list_add_sorted(struct browser_handle *h, struct file_button *add) { struct file_button *file; struct list_head *item; list_for_each(item,&h->files) { file = list_entry(item, struct file_button, window); if (file_cmp_alpha(add,file) <= 0) { list_add_tail(&add->window,&file->window); return; } } list_add_tail(&add->window,&h->files); } static Boolean browser_readdir(XtPointer clientdata) { struct browser_handle *h = clientdata; struct file_button *file; struct list_head *item; struct dirent *dirent; WidgetList children; struct file_button *lastdir = NULL; Cardinal nchildren; XmString str,elem; DIR *dir; unsigned int len; /* status line */ str = XmStringGenerate("scanning ", NULL, XmMULTIBYTE_TEXT, NULL); elem = XmStringGenerate(h->dirname, NULL, XmMULTIBYTE_TEXT, NULL); str = XmStringConcatAndFree(str,elem); elem = XmStringGenerate(" ...", NULL, XmMULTIBYTE_TEXT, NULL); str = XmStringConcatAndFree(str,elem); XtVaSetValues(h->status,XmNlabelString,str,NULL); XmStringFree(str); ptr_busy(); /* read + sort dir */ dir = opendir(h->dirname); if (NULL == dir) { fprintf(stderr,"opendir %s: %s\n",h->dirname,strerror(errno)); return -1; } h->dirs = 0; h->sfiles = 0; h->afiles = 0; while (NULL != (dirent = readdir(dir))) { /* skip dotfiles */ if (dirent->d_name[0] == '.' && 0 != strcmp(dirent->d_name,"..")) continue; /* get memory */ file = malloc(sizeof(*file)); memset(file,0,sizeof(*file)); /* get file type */ file->basename = strdup(dirent->d_name); file->d_type = dirent->d_type; if (0 == strcmp(dirent->d_name, "..")) { char *slash; file->filename = strdup(h->dirname); slash = strrchr(file->filename,'/'); if (slash == file->filename) slash++; *slash = 0; } else { len = strlen(h->dirname)+strlen(file->basename)+4; file->filename = malloc(len); if (0 == strcmp(h->dirname,"/")) { sprintf(file->filename,"/%s",file->basename); } else { sprintf(file->filename,"%s/%s",h->dirname, file->basename); } } if (file->d_type != DT_UNKNOWN) { file->st.st_mode = DTTOIF(file->d_type); } else { if (-1 == stat(file->filename, &file->st)) { fprintf(stderr,"stat %s: %s\n", file->filename,strerror(errno)); } } /* user-specified filter */ if (S_ISDIR(file->st.st_mode)) { h->dirs++; if (h->lastdir && 0 == strcmp(h->lastdir,file->filename)) { lastdir = file; } } else { h->afiles++; if (h->filter && 0 != fnmatch(h->filter,dirent->d_name,0)) { free(file); continue; } else h->sfiles++; } list_add_sorted(h,file); } closedir(dir); /* create & manage widgets */ list_for_each(item,&h->files) { file = list_entry(item, struct file_button, window); file_createwidgets(h->container, file); } nchildren = XmContainerGetItemChildren(h->container,NULL,&children); XtManageChildren(children,nchildren); if (nchildren) XtFree((XtPointer)children); container_relayout(h->container); if (h->lastdir) { if (lastdir) { if (debug) fprintf(stderr,"lastdir: %s\n",h->lastdir); XtVaSetValues(h->container, XmNinitialFocus, lastdir->widget, NULL); // XmScrollVisible(h->scroll, lastdir->widget, 25, 25); // XtSetKeyboardFocus(h->shell,h->container); } free(h->lastdir); h->lastdir = NULL; } XtVaSetValues(h->shell,XtNtitle,h->dirname,NULL); ptr_idle(); /* start bg processing */ h->item = h->files.next; h->wproc = XtAppAddWorkProc(app_context,browser_statfiles,h); return TRUE; } static void browser_bgcancel(struct browser_handle *h) { if (h->wproc) XtRemoveWorkProc(h->wproc); h->wproc = 0; } /*----------------------------------------------------------------------*/ static void browser_cd(struct browser_handle *h, char *dir) { /* build new dir path */ if (h->lastdir) free(h->lastdir); h->lastdir = h->dirname; h->dirname = strdup(dir); /* cleanup old stuff + read dir */ browser_bgcancel(h); container_delwidgets(h->container); h->wproc = XtAppAddWorkProc(app_context,browser_readdir,h); } static void browser_filter_done(Widget widget, XtPointer clientdata, XtPointer call_data) { struct browser_handle *h = clientdata; XmSelectionBoxCallbackStruct *cb = call_data; char *filter; if (cb->reason == XmCR_OK) { filter = XmStringUnparse(cb->value,NULL, XmMULTIBYTE_TEXT,XmMULTIBYTE_TEXT, NULL,0,0); if (h->filter) free(h->filter); h->filter = NULL; if (strlen(filter) > 0) h->filter = strdup(filter); XtFree(filter); if (debug) fprintf(stderr,"filter: %s\n", h->filter ? h->filter : "[none]"); browser_bgcancel(h); container_delwidgets(h->container); h->wproc = XtAppAddWorkProc(app_context,browser_readdir,h); } XtDestroyWidget(widget); } static void browser_filter(Widget widget, XtPointer clientdata, XtPointer call_data) { struct browser_handle *h = clientdata; Widget shell; shell = XmCreatePromptDialog(h->shell,"filter",NULL,0); XtUnmanageChild(XmSelectionBoxGetChild(shell,XmDIALOG_HELP_BUTTON)); XtAddCallback(shell,XmNokCallback,browser_filter_done,h); XtAddCallback(shell,XmNcancelCallback,browser_filter_done,h); XtManageChild(shell); } static void browser_nofilter(Widget widget, XtPointer clientdata, XtPointer call_data) { struct browser_handle *h = clientdata; if (!h->filter) return; if (debug) fprintf(stderr,"filter: reset\n"); free(h->filter); h->filter = NULL; browser_bgcancel(h); container_delwidgets(h->container); h->wproc = XtAppAddWorkProc(app_context,browser_readdir,h); } /*----------------------------------------------------------------------*/ static void browser_action_cb(Widget widget, XtPointer clientdata, XtPointer call_data) { XmContainerSelectCallbackStruct *cd = call_data; struct browser_handle *h = clientdata; struct stat st; char *file; if (XmCR_DEFAULT_ACTION == cd->reason && 1 == cd->selected_item_count) { file = XtName(cd->selected_items[0]); if (debug) fprintf(stderr,"browser: action %s\n", file); if (-1 == stat(file,&st)) { fprintf(stderr,"stat %s: %s\n",file,strerror(errno)); return; } if (S_ISDIR(st.st_mode)) browser_cd(h,file); if (S_ISREG(st.st_mode)) new_file(file,1); } } static void browser_bookmark_cb(Widget widget, XtPointer clientdata, XtPointer call_data) { struct browser_handle *h = clientdata; browser_cd(h, cfg_get_str(O_BOOKMARKS, XtName(widget))); } /*----------------------------------------------------------------------*/ static void browser_destroy(Widget widget, XtPointer clientdata, XtPointer call_data) { struct browser_handle *h = clientdata; if (debug) fprintf(stderr,"browser: destroy\n"); browser_bgcancel(h); ptr_unregister(h->shell); free(h); } static char* browser_fixpath(char *dir) { char path[1024]; char *s,*d; memset(path,0,sizeof(path)); if (dir[0] == '/') { /* absolute */ strncpy(path,dir,sizeof(path)-1); } else { /* relative */ getcwd(path,sizeof(path)-1); if (strlen(path)+strlen(dir)+4 < sizeof(path)) { strcat(path,"/"); strcat(path,dir); } } for (s = d = path; *s != 0;) { if (0 == strncmp(s,"//",2)) { s++; continue; } if (0 == strncmp(s,"/./",3)) { s+=2; continue; } if (0 == strcmp(s,"/")) s++; if (0 == strcmp(s,"/.")) s+=2; *d = *s; s++, d++; } return strdup(path); } void browser_window(char *dirname) { Widget form,menubar,menu,push,clip; struct browser_handle *h; Arg args[8]; char *list; int n = 0; h = malloc(sizeof(*h)); if (NULL == h) { fprintf(stderr,"out of memory"); return; } memset(h,0,sizeof(*h)); INIT_LIST_HEAD(&h->files); h->dirname = browser_fixpath(dirname); h->shell = XtVaAppCreateShell("browser","Ida", topLevelShellWidgetClass, dpy, XtNclientLeader,app_shell, XmNdeleteResponse,XmDESTROY, NULL); XmdRegisterEditres(h->shell); XtAddCallback(h->shell,XtNdestroyCallback,browser_destroy,h); /* widgets */ form = XtVaCreateManagedWidget("form", xmFormWidgetClass, h->shell, NULL); menubar = XmCreateMenuBar(form,"cbar",NULL,0); XtManageChild(menubar); h->status = XtVaCreateManagedWidget("status",xmLabelWidgetClass, form, NULL); /* scrolled container */ h->details[0] = XmStringGenerate("Image", NULL, XmMULTIBYTE_TEXT,NULL); h->details[DETAIL_SIZE+1] = XmStringGenerate("Size", NULL, XmMULTIBYTE_TEXT,NULL); h->details[DETAIL_COMMENT+1] = XmStringGenerate("Comment", NULL, XmMULTIBYTE_TEXT,NULL); XtSetArg(args[n], XmNdetailColumnHeading, h->details); n++; XtSetArg(args[n], XmNdetailColumnHeadingCount, DETAIL_COUNT+1); n++; h->scroll = XmCreateScrolledWindow(form, "scroll", NULL, 0); XtManageChild(h->scroll); h->container = XmCreateContainer(h->scroll,"container", args,n); XtManageChild(h->container); XtAddCallback(h->container,XmNdefaultActionCallback, browser_action_cb,h); XtAddCallback(h->scroll, XmNtraverseObscuredCallback, container_traverse_cb, NULL); XtAddCallback(h->container,XmNconvertCallback, container_convert_cb,h); XtVaGetValues(h->scroll,XmNclipWindow,&clip,NULL); XtAddEventHandler(clip,StructureNotifyMask,True,container_resize_eh,NULL); /* menu - file */ menu = XmCreatePulldownMenu(menubar,"fileM",NULL,0); XtVaCreateManagedWidget("file",xmCascadeButtonWidgetClass,menubar, XmNsubMenuId,menu,NULL); push = XtVaCreateManagedWidget("close",xmPushButtonWidgetClass,menu,NULL); XtAddCallback(push,XmNactivateCallback,destroy_cb,h->shell); /* menu - edit */ menu = XmCreatePulldownMenu(menubar,"editM",NULL,0); XtVaCreateManagedWidget("edit",xmCascadeButtonWidgetClass,menubar, XmNsubMenuId,menu,NULL); container_menu_edit(menu,h->container, 0,1,0,0); /* menu - view */ menu = XmCreatePulldownMenu(menubar,"viewM",NULL,0); XtVaCreateManagedWidget("view",xmCascadeButtonWidgetClass,menubar, XmNsubMenuId,menu,NULL); container_menu_view(menu,h->container); XtVaCreateManagedWidget("sep",xmSeparatorWidgetClass,menu,NULL); push = XtVaCreateManagedWidget("filter",xmPushButtonWidgetClass,menu,NULL); XtAddCallback(push,XmNactivateCallback,browser_filter,h); push = XtVaCreateManagedWidget("freset",xmPushButtonWidgetClass,menu,NULL); XtAddCallback(push,XmNactivateCallback,browser_nofilter,h); /* menu - ops */ menu = XmCreatePulldownMenu(menubar,"opsM",NULL,0); XtVaCreateManagedWidget("ops",xmCascadeButtonWidgetClass,menubar, XmNsubMenuId,menu,NULL); container_menu_ops(menu,h->container); /* menu - dirs (bookmarks) */ menu = XmCreatePulldownMenu(menubar,"dirsM",NULL,0); XtVaCreateManagedWidget("dirs",xmCascadeButtonWidgetClass,menubar, XmNsubMenuId,menu,NULL); for (list = cfg_entries_first(O_BOOKMARKS); list != NULL; list = cfg_entries_next(O_BOOKMARKS,list)) { push = XtVaCreateManagedWidget(list,xmPushButtonWidgetClass,menu,NULL); XtAddCallback(push,XmNactivateCallback,browser_bookmark_cb,h); } /* read dir and show window */ container_spatial_cb(NULL,h->container,NULL); browser_readdir(h); XtPopup(h->shell,XtGrabNone); ptr_register(h->shell); } void browser_ac(Widget widget, XEvent *event, String *params, Cardinal *num_params) { if (*num_params > 0) browser_window(params[0]); else browser_window("."); } fbi-2.10/fbi.man.fr0000644000175000017500000002176512506525033012203 0ustar jmmjmm.TH FBI 1 "(c) 1999-2012 Gerd Hoffmann" "FBI 2.09" "Visionneuse d'image pour le framebuffer Linux" \# \# .SH NOM \# \# fbi - Visionneuse d'image pour le framebuffer Linux .SH SYNOPSIS \fBfbi\fP [\fIoptions\fP] \fIfichier …\fP \# \# .SH DESCRIPTION .BR Fbi affiche les fichiers indiqués dans une console linux en utilisant le framebuffer. Les formats \fIPhotoCD\fP, \fIjpeg\fP, \fIppm\fP, \fIgif\fP, \fItiff\fP, \fIxpm\fP, \fIxwd\fP, \fIbmp\fP, \fIpng\fP and \fIwebp\fP sont pris en charge nativement. Pour les autres, .BR fbi essaye d'utiliser l'utilitaire .BR "convert" "(1)" .BR "" "d'" "ImageMagick" "(1)." \# \# .SH OPTIONS .TP .B -h, --help Afficher le résumé des commandes .TP .B -V, --version Afficher le numéro de version de \fBfbi\fP. .TP .B --store Sauvegader les arguments de la ligne de commande dans le fichier de configuration \fI~/.fbirc\fP. .TP .BI "-l" "\ fichier" ", --list" "\ fichier" Lit une liste de fichiers image depuis un \fIfichier\fP. .TP .B -P, --text Activer le mode de rendu de texte. Dans ce mode .BR fbi affichera les images de grande taille sans marge vertical (par défaut l'image est centrée). La commande \fBESPACE\fP essayera d'abord de faire défiler l'écran vers le bas et ira à l'image suivante seulement s'il est déjà en bas de la page. Très utile pour visualiser des images qui sont des pages de texte, tout ce dont vous avez besoin pour lire la suite du texte est de presser espace… .TP .B -a, --autozoom Activer le zoom autommatique. .BR Fbi choisira automatiquement le facteur de zoom le plus adapté lors du argement chd'une nouvelle image. .TP .B --(no)autoup Comme autozoom, mais n'accepte que l'agrandissement. .TP .B --(no)autodown Comme autozoom, mais n'accepte que la réduction. .TP .B --(no)fitwidth Utiliser seulement la largeur pour la mise à l'échelle automatique. .TP .B -v, --(no)verbose Être loquace : activer la barre d'état en bas de l'écran (activé par défaut). .TP .B -u, --(no)random Mélanger l'ordre des noms de fichier. .TP .B --(no)comments Afficher les balises de commentaire (s'il en existe) au lieu du nom de fichier. Probablement utile si vous avez ajouté des commentaires raisonnables par vous-même (en utilisant .BR "wrjpgcom" "(1)" par exemple), autrement \fIa priori\fP vous verrez seulement les noms des logiciels qui ont servi à créer l'image. .TP .B -e, --(no)edit Activer les commandes d'édition. .TP .B --(no)backup Créer une sauvegarde des fichiers (lors de la modification des images). .TP .B -p, --(no)preserve Conserver l'horodatage (lors de la modification des images). .TP .B --(no)readahead Mettre en cache les entêtes des images. .TP .BI "--cachemem" "\ taille" \fITaille\fP du cache des images en mégaoctets (256 par défaut) .TP .BI "--blend" "\ durée" \fIDurée\fP de mélange des images en millisecondes. .TP .BI "-T" "\ n" ", --vt" "\ n" Démarrer dans la console virtuelle \fIn\fP. .TP .BI "-s" "\ n" ", --scroll" "\ n" Définir un pas de défilement de \fIn\fP pixels (50 par défaut). .TP .BI "-t" "\ n" ", --timeout" "\ n" Démarre un diaporama perpétuel dont chaque image est chargée avec un intervalle de \fIn\fP secondes sans presser aucune touche. .TP .B -1, --(no)once Ne pas boucler (utiliser seulement avec \fB-t\fP). .TP .BI "-r" "\ n" ", --resolution" "\ n" Sélectionner la résolution, \fIn = 1..5\fP (3 par défaut, seulement pour \fIPhotoCD\fP). .TP .BI "-g" "\ n" ", --gamma" "\ n" Correction gamma. Nécessite un visuel en \fIPseudocolor\fP ou \fIDirectcolor\fP, ne fonctionne pas en \fITruecolor\fP (1 par défaut). .TP .BI "-f" "\ " ", --font" "\ " Sélectionner une police. \fI\fP peut prendre n'importe quelle valeur acceptée par fontconfig (voir .BR "fonts\-conf" "(5))." Essayez .BR "fc\-list" "(1)" pour obtenir une liste des polices connues du système. Le fichier de configuration de fontconfig est évalué autant que possible, de sorte que toutes les définitions génériques (tel que mono, sans) fonctionneront parfaitement. Il est recommandé d'utiliser des polices à espacement fixe, les zones de texte (aide, données exif) n'en seront que plus agréables à lire. .TP .BI "-d" "\ /dev/fbN" ", --device" "\ /dev/fbN" Utiliser le framebuffer \fI/dev/fbN\fP. Par défaut, celui sur lequel la console virtuelle est attachée. .TP .BI "-m" "\ videomode" ", --mode" "\ videomode" Nom du mode vidéo à utiliser (le mode vidéo doit être présent dans \fI/etc/fb.modes\fP). Par défaut le mode vidéo reste inchangé. \# \# .SH ENVIRONMENT .BR Fbi utilise les variables d'environnement suivantes : .TP .BR FBGAMMA Cette variable peut être utilisée pour définir une correction gamma par défaut. \# \# .SH "USAGE DES COMMANDES" Les commandes prennent effet immédiatement ; il n'est pas nécessaire de taper entrée. .PP Pour les commandes suivantes, \fIi\fP est un argument numérique. .SS Défilement .TP \fBFLÈCHE_GAUCHE\fP, \fBFLÈCHE_DROITE\fP, \fBFLÈCHE_HAUT\fP, \fBFLÈCHE_BAS\fP Faire défiler les grandes images. .TP \fBÉCRAN_PRÉCÉDENT\fP, \fBk\fP Image précédente. .TP \fBÉCRAN_SUIVANT\fP, \fBSPACE\fP, \fBj\fP Image suivante. .TP \fIi\fP\fBg\fP Atteindre l'image n°\fIi\fP. .TP \fBENTRÉE\fP Écrire le nom du fichier de l'image courante vers .BR "stdout" "(3)," puis aller à l'image suivante. .P Les touches \fBENTRÉE\fP et \fBESPACE\fP peuvent être utilisées pour créer une liste de fichiers pendant la visualisation des images et utiliser plus tard cette liste pour un traitement par lot : .P .in +4n \fIfbi\ fichier1.gif\ fichier2.jpg\ fichier3.jpg >\ listefichierimage.lst\fP .in .P .in +4n quelques \fBENTRÉE\fP et \fBESPACE\fP… .P .in +4n \fIfbi\ -l\ listefichierimage.lst\fP .in .SS Zoom .TP \fBa\fP Zoom autommatique. .TP \fB+\fP Avant. .TP \fB-\fP Arrière. .TP \fIi\fP\fBs\fP Positionner le facteur de zoom à \fIi\fP%. .SS Autres .TP \fBESQ\fP, \fBq\fP Quitter. .TP \fBv\fP Basculer l'affichage de la barre d'état. .TP \fBh\fP Afficher une zone de texte contenant un bref message d'aide. .TP \fBi\fP Afficher une zone de texte avec quelques informations \fIEXIF\fP. .TP \fBp\fP Mettre en pause le diaporama (si démarré avec \fB-t\fP, basculer). .SS Mode Édition .BR Fbi offre aussi quelques fonctionnalités très basiques de modification d'image. Vous devez lancer .BR fbi avec l'option \fI-e\fP pour pouvoir les utiliser. .TP \fBD\fP, \fBShift+d\fP Supprimer l'image. .TP \fBr\fP Rotation de 90 degrés dans le sens des aiguilles d'une montre. .TP \fBl\fP Rotation de 90 degrés dans le sens contraire des aiguilles d'une montre. .TP \fBx\fP Rotation d'axe horizontal (haut / bas). .TP \fBy\fP Rotation d'axe vertical (gauche / droite). .P La fonction de suppression actuelle nécessite une lettre \fBD\fP en capitale, ainsi vous devez taper \fBShift+d\fP. Ceci évite de supprimer des images par erreur en l'absence d'un système d'alerte correcte : Si vous demander à .BR fbi de supprimer une image, il la supprimera sans confirmation. .P La fonction de rotation actuelle marche pour les images \fIJPEG\fP uniquement. Elle effectue une transformation sans perte de données de l'image. \# \# .SH BOGUES .BR Fbi nécessite un accès en lecture/écriture aux framebuffers (\fI/dev/fbN\fP), c-à-d que vous devez vous assurer que .BR fbi peut ouvrir les périphériques en mode lecture/écriture. À mon humble avis, la manière la plus élégante consiste à utiliser .BR PAM (7) pour affecter la propriété des périphériques à l'utilisateur connecté sur la console. Une alternative est de créer un groupe, affecter la propriété des fichiers spéciaux de ce groupe et ajouter les utilisateurs autorisés à utiliser le framebuffer dans ce groupe. Vous pouvez également rendre les fichiers spéciaux accessibles en écriture au monde entier, mais soyez conscient des implications pour la sécurité. Toutefois, sur un ordinateur personnel, c'est peut-être la meilleure solution. .P .BR Fbi doit également pouvoir accéder à la console linux (\fI/dev/ttyN\fP) pour manipuler correctement les commutateurs de console. Ce n'est évidemment pas un problème pour les consoles de connexion, mais il \fBne\fP fonctionnera avec aucun des pseudo-terminaux (xterm, ssh, screen, …). \# \# .SH "VOIR AUSSI" .BR convert (1), .BR fbset (1), .BR fc-list (1), .BR imagemagick (1), .BR wrjpgcom (1), .BR fonts-conf (5), .BR PAM (7) \# \# .SH TRADUCTEUR Stéphane Aulery .BR \# \# .SH AUTEUR Gerd Hoffmann .BR \# \# .SH COPYRIGHT Copyright (c) 1999-2012 Gerd Hoffmann .P 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. .P 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. .P 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., 675 Mass Ave, Cambridge, MA 02139, USA. fbi-2.10/idaconfig.h0000644000175000017500000000147112506525033012424 0ustar jmmjmm#include "parseconfig.h" #define O_OPTIONS "config", "options" #define O_BOOKMARKS "config", "bookmarks" #define O_AUTOZOOM O_OPTIONS, "autozoom" #define O_PHOTOCD_RES O_OPTIONS, "photocd_res" #define O_SANE_RES O_OPTIONS, "sane_res" #define O_ICON_SMALL O_OPTIONS, "icon_small" #define O_ICON_LARGE O_OPTIONS, "icon_large" #define GET_AUTOZOOM() cfg_get_bool(O_AUTOZOOM, 1) #define GET_PHOTOCD_RES() cfg_get_int(O_PHOTOCD_RES, 3) #define GET_SANE_RES() cfg_get_int(O_SANE_RES, 300) #define GET_ICON_SMALL() cfg_get_int(O_ICON_SMALL, 32) #define GET_ICON_LARGE() cfg_get_int(O_ICON_LARGE, 96) /* -------------------------------------------------------------------------- */ char *ida_lists; void ida_init_config(void); void ida_read_config(void); void ida_write_config(void); fbi-2.10/browser.h0000644000175000017500000000017312506525033012162 0ustar jmmjmmvoid browser_window(char *dirname); void browser_ac(Widget widget, XEvent *event, String *params, Cardinal *num_params); fbi-2.10/selections.h0000644000175000017500000000115712506525033012652 0ustar jmmjmmextern Atom XA_TARGETS, XA_DONE; extern Atom _MOTIF_EXPORT_TARGETS; extern Atom _MOTIF_CLIPBOARD_TARGETS; extern Atom _MOTIF_DEFERRED_CLIPBOARD_TARGETS; extern Atom _MOTIF_SNAPSHOT; extern Atom _MOTIF_LOSE_SELECTION; extern Atom XA_FILE_NAME, XA_FILE; extern Atom _NETSCAPE_URL; extern Atom MIME_TEXT_URI_LIST; Atom sel_unique_atom(Widget widget); void selection_dest(Widget w, XtPointer ignore, XtPointer call_data); void selection_convert(Widget widget, XtPointer ignore, XtPointer call_data); void ipc_ac(Widget widget, XEvent *event, String *argv, Cardinal *argc); void dnd_add(Widget widget); void ipc_init(void); fbi-2.10/fallback.pl0000755000175000017500000000055112506525033012425 0ustar jmmjmm#!/usr/bin/perl -w # # build header file from # use strict; while (my $line = <>) { chomp $line; # ignore comments next if $line =~ /^!/; # next if $line =~ /^\s*$/; # quote stuff $line =~ s/\\/\\\\/g; $line =~ s/\"/\\\"/g; # continued line? if ($line =~ s/\\\\$//) { printf "\"%s\"\n",$line; next; } # write out printf "\"%s\",\n",$line; } fbi-2.10/fileops.h0000644000175000017500000000006712506525033012142 0ustar jmmjmmvoid job_submit(char *op, char *filename, char *args); fbi-2.10/GNUmakefile0000644000175000017500000001477212506525033012412 0ustar jmmjmm# config srcdir = . VPATH = $(srcdir) -include Make.config include $(srcdir)/mk/Variables.mk resdir = $(DESTDIR)$(RESDIR) # fixup flags CFLAGS += -DVERSION='"$(VERSION)"' -I$(srcdir) CFLAGS += -Wno-pointer-sign # default target all: build # what to build TARGETS := exiftran thumbnail.cgi ifeq ($(HAVE_LINUX_FB_H),yes) TARGETS += fbi endif ifeq ($(HAVE_MOTIF),yes) TARGETS += ida endif ################################################################# # poor man's autoconf ;-) include $(srcdir)/mk/Autoconf.mk ac_jpeg_ver = $(shell \ $(call ac_init,for libjpeg version);\ $(call ac_s_cmd,echo JPEG_LIB_VERSION \ | cpp -include jpeglib.h | tail -n 1);\ $(call ac_fini)) define make-config LIB := $(LIB) RESDIR := $(call ac_resdir) HAVE_ENDIAN_H := $(call ac_header,endian.h) HAVE_LINUX_FB_H := $(call ac_header,linux/fb.h) HAVE_NEW_EXIF := $(call ac_header,libexif/exif-log.h) HAVE_GLIBC := $(call ac_func,fopencookie) HAVE_STRSIGNAL := $(call ac_func,strsignal) HAVE_LIBPCD := $(call ac_lib,pcd_open,pcd) HAVE_LIBGIF := $(call ac_lib,DGifOpenFileName,gif) HAVE_LIBPNG := $(call ac_lib,png_read_info,png,-lz) HAVE_LIBTIFF := $(call ac_lib,TIFFOpen,tiff) HAVE_LIBWEBP := $(call ac_lib,WebPDecodeRGBA,webp) #HAVE_LIBMAGICK := $(call ac_binary,Magick-config) HAVE_LIBSANE := $(call ac_lib,sane_init,sane) HAVE_LIBCURL := $(call ac_lib,curl_easy_init,curl) HAVE_LIBLIRC := $(call ac_lib,lirc_init,lirc_client) HAVE_MOTIF := $(call ac_lib,XmStringGenerate,Xm,-L/usr/X11R6/$(LIB) -lXpm -lXt -lXext -lX11) JPEG_VER := $(call ac_jpeg_ver) endef # transposing CFLAGS += -Ijpeg/$(JPEG_VER) # transparent http/ftp access using curl depends on fopencookie (glibc) ifneq ($(HAVE_GLIBC),yes) HAVE_LIBCURL := no endif # catch fopen calls for transparent ftp/http access ifeq ($(HAVE_LIBCURL),yes) ida fbi : CFLAGS += -D_GNU_SOURCE ida fbi : LDFLAGS += -Wl,--wrap=fopen endif PKG_CONFIG = pkg-config ######################################################################## # conditional stuff includes = ENDIAN_H STRSIGNAL NEW_EXIF libraries = PCD GIF PNG TIFF WEBP CURL SANE LIRC ida_libs = PCD GIF PNG TIFF WEBP CURL SANE fbi_libs = PCD GIF PNG TIFF WEBP CURL LIRC #MAGICK_CFLAGS = $(shell Magick-config --cflags) #MAGICK_LDFLAGS = $(shell Magick-config --ldflags) #MAGICK_LDLIBS = $(shell Magick-config --libs) #MAGICK_OBJS := rd/magick.o PNG_LDLIBS := -lpng -lz TIFF_LDLIBS := -ltiff WEBP_LDLIBS := -lwebp PCD_LDLIBS := -lpcd GIF_LDLIBS := -lgif SANE_LDLIBS := -lsane CURL_LDLIBS := -lcurl LIRC_LDLIBS := -llirc_client PNG_OBJS := rd/read-png.o wr/write-png.o TIFF_OBJS := rd/read-tiff.o wr/write-tiff.o WEBP_OBJS := rd/read-webp.o PCD_OBJS := rd/read-pcd.o GIF_OBJS := rd/read-gif.o SANE_OBJS := sane.o CURL_OBJS := curl.o LIRC_OBJS := lirc.o # common objs OBJS_READER := readers.o rd/read-ppm.o rd/read-bmp.o rd/read-jpeg.o OBJS_WRITER := writers.o wr/write-ppm.o wr/write-ps.o wr/write-jpeg.o # update various flags depending on HAVE_* CFLAGS += $(call ac_inc_cflags,$(includes)) CFLAGS += $(call ac_lib_cflags,$(libraries)) CFLAGS += $(call ac_lib_mkvar,$(libraries),CFLAGS) LDFLAGS += $(call ac_lib_mkvar,$(libraries),LDFLAGS) # link which conditional libs ida : LDLIBS += $(call ac_lib_mkvar,$(ida_libs),LDLIBS) fbi : LDLIBS += $(call ac_lib_mkvar,$(fbi_libs),LDLIBS) ######################################################################## # rules for the small tools # jpeg/exif libs exiftran : LDLIBS += -ljpeg -lexif -lm thumbnail.cgi : LDLIBS += -lexif -lm exiftran: exiftran.o genthumbnail.o jpegtools.o \ jpeg/$(JPEG_VER)/transupp.o \ filter.o op.o readers.o rd/read-jpeg.o thumbnail.cgi: thumbnail.cgi.o ######################################################################## # rules for ida # object files OBJS_IDA := \ ida.o man.o hex.o x11.o viewer.o dither.o icons.o \ parseconfig.o idaconfig.o fileops.o desktop.o \ RegEdit.o selections.o xdnd.o jpeg/$(JPEG_VER)/transupp.o \ filebutton.o filelist.o browser.o jpegtools.o \ op.o filter.o lut.o color.o \ rd/read-xwd.o rd/read-xpm.o OBJS_IDA += $(call ac_lib_mkvar,$(ida_libs),OBJS) # for X11 + Motif ida : CFLAGS += -I/usr/X11R6/include ida : LDFLAGS += -L/usr/X11R6/$(LIB) ida : LDLIBS += -lXm -lXpm -lXt -lXext -lX11 # jpeg/exif libs ida : LDLIBS += -ljpeg -lexif -lm # RegEdit.c is good old K&R ... RegEdit.o : CFLAGS += -Wno-missing-prototypes -Wno-strict-prototypes -Wno-maybe-uninitialized ida: $(OBJS_IDA) $(OBJS_READER) $(OBJS_WRITER) Ida.ad.h: Ida.ad $(srcdir)/fallback.pl perl $(srcdir)/fallback.pl < $< > $@ logo.h: logo.jpg hexdump -v -e '1/1 "0x%02x,"' < $< > $@ echo >> $@ # make gcc 3.x happy ida.o: Ida.ad.h logo.h ######################################################################## # rules for fbi # object files OBJS_FBI := \ fbi.o fbtools.o fb-gui.o desktop.o \ parseconfig.o fbiconfig.o \ jpegtools.o jpeg/$(JPEG_VER)/transupp.o \ dither.o filter.o op.o OBJS_FBI += $(filter-out wr/%,$(call ac_lib_mkvar,$(fbi_libs),OBJS)) # jpeg/exif libs fbi : CFLAGS += $(shell $(PKG_CONFIG) --cflags freetype2 fontconfig) fbi : LDLIBS += $(shell $(PKG_CONFIG) --libs freetype2 fontconfig) fbi : LDLIBS += -ljpeg -lexif -lm fbi: $(OBJS_FBI) $(OBJS_READER) ######################################################################## # general rules .PHONY: check-libjpeg build install clean distclean realclean build: check-libjpeg $(TARGETS) check-libjpeg: @test -d jpeg/$(JPEG_VER) || \ ( echo "Need files from libjpeg $(JPEG_VER) in jpeg/"; false) install: build $(INSTALL_DIR) $(bindir) $(INSTALL_DIR) $(mandir)/man1 $(INSTALL_BINARY) exiftran $(bindir) $(INSTALL_DATA) $(srcdir)/exiftran.man $(mandir)/man1/exiftran.1 ifeq ($(HAVE_LINUX_FB_H),yes) $(INSTALL_BINARY) fbi $(bindir) $(INSTALL_SCRIPT) fbgs $(bindir) $(INSTALL_DATA) $(srcdir)/fbi.man $(mandir)/man1/fbi.1 $(INSTALL_DATA) $(srcdir)/fbgs.man $(mandir)/man1/fbgs.1 endif ifeq ($(HAVE_MOTIF),yes) $(INSTALL_BINARY) ida $(bindir) $(INSTALL_DATA) $(srcdir)/ida.man $(mandir)/man1/ida.1 $(INSTALL_DIR) $(resdir)/app-defaults $(INSTALL_DATA) $(srcdir)/Ida.ad $(resdir)/app-defaults/Ida endif clean: -rm -f *.o jpeg/$(JPEG_VER)/*.o rd/*.o wr/*.o $(depfiles) core core.* realclean distclean: clean -rm -f Make.config -rm -f $(TARGETS) *~ rd/*~ wr/*~ xpm/*~ Ida.ad.h logo.h include $(srcdir)/mk/Compile.mk -include $(depfiles) ######################################################################## # maintainer stuff include $(srcdir)/mk/Maintainer.mk #sync:: # cp $(srcdir)/../xawtv/common/parseconfig.[ch] $(srcdir) # cp $(srcdir)/../xawtv/console/fbtools.[ch] $(srcdir) fbi-2.10/readers.h0000644000175000017500000000573212506525033012132 0ustar jmmjmm#include "list.h" enum ida_extype { EXTRA_COMMENT = 1, EXTRA_EXIF = 2, }; struct ida_extra { enum ida_extype type; unsigned char *data; unsigned int size; struct ida_extra *next; }; /* image data and metadata */ struct ida_image_info { unsigned int width; unsigned int height; unsigned int dpi; unsigned int npages; struct ida_extra *extra; int thumbnail; unsigned int real_width; unsigned int real_height; }; struct ida_image { struct ida_image_info i; unsigned char *data; }; struct ida_rect { int x1,y1,x2,y2; }; /* load image files */ struct ida_loader { char *magic; int moff; int mlen; char *name; void* (*init)(FILE *fp, char *filename, unsigned int page, struct ida_image_info *i, int thumbnail); void (*read)(unsigned char *dst, unsigned int line, void *data); void (*done)(void *data); struct list_head list; }; /* filter + operations */ struct ida_op { char *name; void* (*init)(struct ida_image *src, struct ida_rect *rect, struct ida_image_info *i, void *parm); void (*work)(struct ida_image *src, struct ida_rect *rect, unsigned char *dst, int line, void *data); void (*done)(void *data); }; void* op_none_init(struct ida_image *src, struct ida_rect *rect, struct ida_image_info *i, void *parm); void op_none_done(void *data); void op_free_done(void *data); /* ----------------------------------------------------------------------- */ /* resolution */ #define res_cm_to_inch(x) ((x * 2540 + 5) / 1000) #define res_m_to_inch(x) ((x * 2540 + 5) / 100000) #define res_inch_to_m(x) ((x * 100000 + 5) / 2540) /* ----------------------------------------------------------------------- */ /* helpers */ void load_bits_lsb(unsigned char *dst, unsigned char *src, int width, int on, int off); void load_bits_msb(unsigned char *dst, unsigned char *src, int width, int on, int off); void load_gray(unsigned char *dst, unsigned char *src, int width); void load_graya(unsigned char *dst, unsigned char *src, int width); void load_rgba(unsigned char *dst, unsigned char *src, int width); int load_add_extra(struct ida_image_info *info, enum ida_extype type, unsigned char *data, unsigned int size); struct ida_extra* load_find_extra(struct ida_image_info *info, enum ida_extype type); int load_free_extras(struct ida_image_info *info); /* ----------------------------------------------------------------------- */ /* other */ extern int debug; extern struct ida_loader ppm_loader; extern struct ida_loader jpeg_loader; extern struct ida_loader sane_loader; extern struct ida_writer ps_writer; extern struct ida_writer jpeg_writer; /* lists */ #define __init __attribute__ ((constructor)) #define __fini __attribute__ ((destructor)) extern struct list_head loaders; void load_register(struct ida_loader *loader); fbi-2.10/fbi.c0000644000175000017500000011320012506525033011226 0ustar jmmjmm/* * image viewer, for framebuffer devices * * (c) 1998-2012 Gerd Hoffmann * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_LIBLIRC # include "lirc/lirc_client.h" # include "lirc.h" #endif #include "readers.h" #include "fbtools.h" #include "fb-gui.h" #include "filter.h" #include "desktop.h" #include "fbiconfig.h" #include "transupp.h" /* Support routines for jpegtran */ #include "jpegtools.h" #define TRUE 1 #define FALSE 0 #undef MAX #define MAX(x,y) ((x)>(y)?(x):(y)) #undef MIN #define MIN(x,y) ((x)<(y)?(x):(y)) #define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0])) #define KEY_EOF -1 /* ^D */ #define KEY_ESC -2 #define KEY_SPACE -3 #define KEY_Q -4 #define KEY_PGUP -5 #define KEY_PGDN -6 #define KEY_TIMEOUT -7 #define KEY_TAGFILE -8 #define KEY_PLUS -9 #define KEY_MINUS -10 #define KEY_VERBOSE -11 #define KEY_ASCALE -12 #define KEY_DESC -13 /* with arg */ #define KEY_GOTO -100 #define KEY_SCALE -101 #define KEY_DELAY -102 /* edit */ #define KEY_DELETE -200 #define KEY_ROT_CW -201 #define KEY_ROT_CCW -202 #define KEY_FLIP_V -203 #define KEY_FLIP_H -204 #define DEFAULT_DEVICE "/dev/fb0" /* ---------------------------------------------------------------------- */ /* lirc fd */ int lirc = -1; /* variables for read_image */ int32_t lut_red[256], lut_green[256], lut_blue[256]; int pcd_res = 3; int v_steps = 50; int h_steps = 50; int textreading = 0, redraw = 0, statusline = 1; int fitwidth; /* file list */ struct flist { /* file list */ int nr; int tag; char *name; struct list_head list; /* image cache */ int seen; int top; int left; int text_steps; float scale; struct ida_image *fimg; struct ida_image *simg; struct list_head lru; }; static LIST_HEAD(flist); static LIST_HEAD(flru); static int fcount; static struct flist *fcurrent; static struct ida_image *img; /* accounting */ static int img_cnt, min_cnt = 2, max_cnt = 16; static int img_mem, max_mem_mb; /* framebuffer */ char *fbdev = NULL; char *fbmode = NULL; int fd, switch_last, debug; unsigned short red[256], green[256], blue[256]; struct fb_cmap cmap = { 0, 256, red, green, blue }; static float fbgamma = 1; /* Command line options. */ int autodown; int autoup; int comments; int transparency = 40; int timeout; int backup; int preserve; int read_ahead; int editable; int blend_msecs; int perfmon = 0; /* font handling */ static char *fontname = NULL; static FT_Face face; /* ---------------------------------------------------------------------- */ /* fwd declarations */ static struct ida_image *flist_img_get(struct flist *f); static void *flist_malloc(size_t size); static void flist_img_load(struct flist *f, int prefetch); /* ---------------------------------------------------------------------- */ static void version(void) { fprintf(stderr, "fbi version " VERSION ", compiled on %s\n" "(c) 1998-2012 Gerd Hoffmann [SUSE Labs]\n", __DATE__ ); } static void usage(char *name) { char *h; if (NULL != (h = strrchr(name, '/'))) name = h+1; fprintf(stderr, "\n" "This program displays images using the Linux framebuffer device.\n" "Supported formats: PhotoCD, jpeg, ppm, gif, tiff, xwd, bmp, png,\n" "webp. It tries to use ImageMagick's convert for unknown file formats.\n" "\n" "usage: %s [ options ] file1 file2 ... fileN\n" "\n", name); cfg_help_cmdline(stderr,fbi_cmd,4,20,0); cfg_help_cmdline(stderr,fbi_cfg,4,20,40); fprintf(stderr, "\n" "Large images can be scrolled using the cursor keys. Zoom in/out\n" "works with '+' and '-'. Use ESC or 'q' to quit. Space and PgDn\n" "show the next, PgUp shows the previous image. Jumping to a image\n" "works with g. Return acts like Space but additionally prints\n" "prints the filename of the currently displayed image to stdout.\n" "\n"); } /* ---------------------------------------------------------------------- */ static int flist_add(char *filename) { struct flist *f; f = malloc(sizeof(*f)); memset(f,0,sizeof(*f)); f->name = strdup(filename); list_add_tail(&f->list,&flist); INIT_LIST_HEAD(&f->lru); return 0; } static int flist_add_list(char *listfile) { char filename[256]; FILE *list; list = fopen(listfile,"r"); if (NULL == list) { fprintf(stderr,"open %s: %s\n",listfile,strerror(errno)); return -1; } while (NULL != fgets(filename,sizeof(filename)-1,list)) { size_t off = strcspn(filename,"\r\n"); if (off) filename[off] = 0; flist_add(filename); } fclose(list); return 0; } static int flist_del(struct flist *f) { list_del(&f->list); free(f->name); free(f); return 0; } static void flist_renumber(void) { struct list_head *item; struct flist *f; int i = 0; list_for_each(item,&flist) { f = list_entry(item, struct flist, list); f->nr = ++i; } fcount = i; } static int flist_islast(struct flist *f) { return (&flist == f->list.next) ? 1 : 0; } static int flist_isfirst(struct flist *f) { return (&flist == f->list.prev) ? 1 : 0; } static struct flist* flist_first(void) { return list_entry(flist.next, struct flist, list); } static struct flist* flist_last(void) { return list_entry(flist.prev, struct flist, list); } static struct flist* flist_next(struct flist *f, int eof, int loop) { if (flist_islast(f)) { if (eof) return NULL; if (loop) return flist_first(); return f; } return list_entry(f->list.next, struct flist, list); } static struct flist* flist_prev(struct flist *f, int loop) { if (flist_isfirst(f)) { if (loop) return flist_last(); return f; } return list_entry(f->list.prev, struct flist, list); } static struct flist* flist_goto(int dest) { struct list_head *item; struct flist *f; list_for_each(item,&flist) { f = list_entry(item, struct flist, list); if (f->nr == dest) return f; } return NULL; } static void flist_randomize(void) { struct flist *f; int count; srand((unsigned)time(NULL)); flist_renumber(); for (count = fcount; count > 0; count--) { f = flist_goto((rand() % count)+1); list_del(&f->list); list_add_tail(&f->list,&flist); flist_renumber(); } } static void flist_print_tagged(FILE *fp) { struct list_head *item; struct flist *f; list_for_each(item,&flist) { f = list_entry(item, struct flist, list); if (f->tag) fprintf(fp,"%s\n",f->name); } } /* ---------------------------------------------------------------------- */ static void shadow_draw_image(struct ida_image *img, int xoff, int yoff, unsigned int first, unsigned int last, int weight) { unsigned int dwidth = MIN(img->i.width, fb_var.xres); unsigned int dheight = MIN(img->i.height, fb_var.yres); unsigned int data, offset, y, xs, ys; if (100 == weight) shadow_clear_lines(first, last); else shadow_darkify(0, fb_var.xres-1, first, last, 100 - weight); /* offset for image data (image > screen, select visible area) */ offset = (yoff * img->i.width + xoff) * 3; /* offset for video memory (image < screen, center image) */ xs = 0, ys = 0; if (img->i.width < fb_var.xres) xs += (fb_var.xres - img->i.width) / 2; if (img->i.height < fb_var.yres) ys += (fb_var.yres - img->i.height) / 2; /* go ! */ for (data = 0, y = 0; data < img->i.width * img->i.height * 3 && data / img->i.width / 3 < dheight; data += img->i.width * 3, y++) { if (ys+y < first) continue; if (ys+y > last) continue; if (100 == weight) shadow_draw_rgbdata(xs, ys+y, dwidth, img->data + data + offset); else shadow_merge_rgbdata(xs, ys+y, dwidth, weight, img->data + data + offset); } } static void status_prepare(void) { struct ida_image *img = flist_img_get(fcurrent); int y1 = fb_var.yres - (face->size->metrics.height >> 6); int y2 = fb_var.yres - 1; if (img) { shadow_draw_image(img, fcurrent->left, fcurrent->top, y1, y2, 100); shadow_darkify(0, fb_var.xres-1, y1, y2, transparency); } else { shadow_clear_lines(y1, y2); } shadow_draw_line(0, fb_var.xres-1, y1-1, y1-1); } static void status_update(unsigned char *desc, char *info) { int yt = fb_var.yres + (face->size->metrics.descender >> 6); wchar_t str[128]; if (!statusline) return; status_prepare(); swprintf(str,ARRAY_SIZE(str),L"%s",desc); shadow_draw_string(face, 0, yt, str, -1); if (info) { swprintf(str,ARRAY_SIZE(str), L"[ %s ] H - Help", info); } else { swprintf(str,ARRAY_SIZE(str), L"| H - Help"); } shadow_draw_string(face, fb_var.xres, yt, str, 1); shadow_render(); } static void status_error(unsigned char *msg) { int yt = fb_var.yres + (face->size->metrics.descender >> 6); wchar_t str[128]; status_prepare(); swprintf(str,ARRAY_SIZE(str), L"%s", msg); shadow_draw_string(face, 0, yt, str, -1); shadow_render(); sleep(2); } static void status_edit(unsigned char *msg, int pos) { int yt = fb_var.yres + (face->size->metrics.descender >> 6); wchar_t str[128]; status_prepare(); swprintf(str,ARRAY_SIZE(str), L"%s", msg); shadow_draw_string_cursor(face, 0, yt, str, pos); shadow_render(); } static void show_exif(struct flist *f) { static unsigned int tags[] = { 0x010f, // Manufacturer 0x0110, // Model 0x0112, // Orientation 0x0132, // Date and Time 0x01e3, // White Point 0x829a, // Exposure Time 0x829d, // FNumber 0x9206, // Subject Distance 0xa40c, // Subject Distance Range 0xa405, // Focal Length In 35mm Film 0x9209, // Flash 0xa002, // Pixel X Dimension 0xa003, // Pixel Y Dimension }; ExifData *ed; ExifEntry *ee; unsigned int tag,l1,l2,len,count,i; const char *title[ARRAY_SIZE(tags)]; char *value[ARRAY_SIZE(tags)]; wchar_t *linebuffer[ARRAY_SIZE(tags)]; if (!visible) return; ed = exif_data_new_from_file(f->name); if (NULL == ed) { status_error("image has no EXIF data"); return; } /* pass one -- get data + calc size */ l1 = 0; l2 = 0; for (tag = 0; tag < ARRAY_SIZE(tags); tag++) { ee = exif_content_get_entry (ed->ifd[EXIF_IFD_0], tags[tag]); if (NULL == ee) ee = exif_content_get_entry (ed->ifd[EXIF_IFD_EXIF], tags[tag]); if (NULL == ee) { title[tag] = NULL; value[tag] = NULL; continue; } title[tag] = exif_tag_get_title(tags[tag]); #ifdef HAVE_NEW_EXIF value[tag] = malloc(128); exif_entry_get_value(ee, value[tag], 128); #else value[tag] = strdup(exif_entry_get_value(ee)); #endif len = strlen(title[tag]); if (l1 < len) l1 = len; len = strlen(value[tag]); if (l2 < len) l2 = len; } /* pass two -- print stuff */ count = 0; for (tag = 0; tag < ARRAY_SIZE(tags); tag++) { if (NULL == title[tag]) continue; linebuffer[count] = malloc(sizeof(wchar_t)*(l1+l2+8)); swprintf(linebuffer[count], l1+l2+8, L"%-*.*s : %-*.*s", l1, l1, title[tag], l2, l2, value[tag]); count++; } shadow_draw_text_box(face, 24, 16, transparency, linebuffer, count); shadow_render(); /* pass three -- free data */ for (tag = 0; tag < ARRAY_SIZE(tags); tag++) if (NULL != value[tag]) free(value[tag]); exif_data_unref (ed); for (i = 0; i < count; i++) free(linebuffer[i]); } static void show_help(void) { static wchar_t *help[] = { L"keyboard commands", L"~~~~~~~~~~~~~~~~~", L" cursor keys - scroll image", L" PgUp, k - previous image", L" PgDn, SPACE, j - next image", L" g - jump to image #i", L"", L" a - autozoom image", L" +/- - zoom in/out", L" s - set zoom to %", L"", L" ESC, q - quit", L" v - toggle statusline", L" h - show this help text", L" i - show EXIF info", L" p - pause slideshow", L"", L"available if started with --edit switch,", L"rotation works for jpeg images only:", L" D, Shift+d - delete image", L" r - rotate 90 degrees clockwise", L" l - rotate 90 degrees counter-clockwise", L" x - mirror image vertically (top / bottom)", L" y - mirror image horizontally (left to right)", }; shadow_draw_text_box(face, 24, 16, transparency, help, ARRAY_SIZE(help)); shadow_render(); } /* ---------------------------------------------------------------------- */ struct termios saved_attributes; int saved_fl; static void tty_raw(void) { struct termios tattr; fcntl(0,F_GETFL,&saved_fl); tcgetattr (0, &saved_attributes); fcntl(0,F_SETFL,O_NONBLOCK); memcpy(&tattr,&saved_attributes,sizeof(struct termios)); tattr.c_lflag &= ~(ICANON|ECHO); tattr.c_cc[VMIN] = 1; tattr.c_cc[VTIME] = 0; tcsetattr (0, TCSAFLUSH, &tattr); } static void tty_restore(void) { fcntl(0,F_SETFL,saved_fl); tcsetattr (0, TCSANOW, &saved_attributes); } /* testing: find key codes */ static void debug_key(char *key) { char linebuffer[128]; int i,len; len = sprintf(linebuffer,"key: "); for (i = 0; key[i] != '\0'; i++) len += snprintf(linebuffer+len, sizeof(linebuffer)-len, "%s%c", key[i] < 0x20 ? "^" : "", key[i] < 0x20 ? key[i] + 0x40 : key[i]); status_update(linebuffer, NULL); } static void console_switch(void) { switch (fb_switch_state) { case FB_REL_REQ: fb_switch_release(); case FB_INACTIVE: visible = 0; break; case FB_ACQ_REQ: fb_switch_acquire(); case FB_ACTIVE: visible = 1; ioctl(fd,FBIOPAN_DISPLAY,&fb_var); shadow_set_palette(fd); shadow_set_dirty(); shadow_render(); break; default: break; } switch_last = fb_switch_state; return; } /* ---------------------------------------------------------------------- */ static void free_image(struct ida_image *img) { if (img) { if (img->data) { img_mem -= img->i.width * img->i.height * 3; free(img->data); } free(img); } } static struct ida_image* read_image(char *filename) { struct ida_loader *loader = NULL; struct ida_image *img; struct list_head *item; char blk[512]; FILE *fp; unsigned int y; void *data; /* open file */ if (NULL == (fp = fopen(filename, "r"))) { fprintf(stderr,"open %s: %s\n",filename,strerror(errno)); return NULL; } memset(blk,0,sizeof(blk)); fread(blk,1,sizeof(blk),fp); rewind(fp); /* pick loader */ list_for_each(item,&loaders) { loader = list_entry(item, struct ida_loader, list); if (NULL == loader->magic) break; if (0 == memcmp(blk+loader->moff,loader->magic,loader->mlen)) break; loader = NULL; } if (NULL == loader) { /* no loader found, try to use ImageMagick's convert */ int p[2]; if (0 != pipe(p)) return NULL; switch (fork()) { case -1: /* error */ perror("fork"); close(p[0]); close(p[1]); return NULL; case 0: /* child */ dup2(p[1], 1 /* stdout */); close(p[0]); close(p[1]); execlp("convert", "convert", "-depth", "8", filename, "ppm:-", NULL); exit(1); default: /* parent */ close(p[1]); fp = fdopen(p[0], "r"); if (NULL == fp) return NULL; loader = &ppm_loader; } } /* load image */ img = malloc(sizeof(*img)); memset(img,0,sizeof(*img)); data = loader->init(fp,filename,0,&img->i,0); if (NULL == data) { fprintf(stderr,"loading %s [%s] FAILED\n",filename,loader->name); free_image(img); return NULL; } img->data = flist_malloc(img->i.width * img->i.height * 3); img_mem += img->i.width * img->i.height * 3; for (y = 0; y < img->i.height; y++) { if (switch_last != fb_switch_state) console_switch(); loader->read(img->data + img->i.width * 3 * y, y, data); } loader->done(data); return img; } static struct ida_image* scale_image(struct ida_image *src, float scale) { struct op_resize_parm p; struct ida_rect rect; struct ida_image *dest; void *data; unsigned int y; dest = malloc(sizeof(*dest)); memset(dest,0,sizeof(*dest)); memset(&rect,0,sizeof(rect)); memset(&p,0,sizeof(p)); p.width = src->i.width * scale; p.height = src->i.height * scale; p.dpi = src->i.dpi; if (0 == p.width) p.width = 1; if (0 == p.height) p.height = 1; data = desc_resize.init(src,&rect,&dest->i,&p); dest->data = flist_malloc(dest->i.width * dest->i.height * 3); img_mem += dest->i.width * dest->i.height * 3; for (y = 0; y < dest->i.height; y++) { if (switch_last != fb_switch_state) console_switch(); desc_resize.work(src,&rect, dest->data + 3 * dest->i.width * y, y, data); } desc_resize.done(data); return dest; } static float auto_scale(struct ida_image *img) { float xs,ys,scale; xs = (float)fb_var.xres / img->i.width; if (fitwidth) return xs; ys = (float)fb_var.yres / img->i.height; scale = (xs < ys) ? xs : ys; return scale; } static int calculate_text_steps(int height, int yres) { int pages = ceil((float)height / yres); int text_steps = ceil((float)height / pages); return text_steps; } /* ---------------------------------------------------------------------- */ static void effect_blend(struct flist *f, struct flist *t) { struct timeval start, now; int msecs, weight = 0; char linebuffer[80]; int pos = 0; int count = 0; gettimeofday(&start, NULL); do { gettimeofday(&now, NULL); msecs = (now.tv_sec - start.tv_sec) * 1000; msecs += (now.tv_usec - start.tv_usec) / 1000; weight = msecs * 100 / blend_msecs; if (weight > 100) weight = 100; shadow_draw_image(flist_img_get(f), f->left, f->top, 0, fb_var.yres-1, 100); shadow_draw_image(flist_img_get(t), t->left, t->top, 0, fb_var.yres-1, weight); if (perfmon) { pos += snprintf(linebuffer+pos, sizeof(linebuffer)-pos, " %d%%", weight); status_update(linebuffer, NULL); count++; } shadow_render(); } while (weight < 100); if (perfmon) { gettimeofday(&now, NULL); msecs = (now.tv_sec - start.tv_sec) * 1000; msecs += (now.tv_usec - start.tv_usec) / 1000; pos += snprintf(linebuffer+pos, sizeof(linebuffer)-pos, " | %d/%d -> %d msec", msecs, count, msecs/count); status_update(linebuffer, NULL); shadow_render(); sleep(2); } } static int svga_show(struct flist *f, struct flist *prev, int timeout, char *desc, char *info, int *nr) { static int paused = 0, skip = KEY_SPACE; struct ida_image *img = flist_img_get(f); int exif = 0, help = 0; int rc; char key[11]; fd_set set; struct timeval limit; char linebuffer[80]; int fdmax; *nr = 0; if (NULL == img) return skip; redraw = 1; for (;;) { if (redraw) { redraw = 0; if (img->i.height <= fb_var.yres) { f->top = 0; } else { if (f->top < 0) f->top = 0; if (f->top + fb_var.yres > img->i.height) f->top = img->i.height - fb_var.yres; } if (img->i.width <= fb_var.xres) { f->left = 0; } else { if (f->left < 0) f->left = 0; if (f->left + fb_var.xres > img->i.width) f->left = img->i.width - fb_var.xres; } if (blend_msecs && prev && prev != f && flist_img_get(prev) && flist_img_get(f)) { effect_blend(prev, f); prev = NULL; } else { shadow_draw_image(img, f->left, f->top, 0, fb_var.yres-1, 100); } status_update(desc, info); shadow_render(); if (read_ahead) { struct flist *f = flist_next(fcurrent,1,0); if (f && !f->fimg) flist_img_load(f,1); status_update(desc, info); shadow_render(); } } if (switch_last != fb_switch_state) { console_switch(); continue; } FD_ZERO(&set); FD_SET(0, &set); fdmax = 1; #ifdef HAVE_LIBLIRC if (-1 != lirc) { FD_SET(lirc,&set); fdmax = lirc+1; } #endif limit.tv_sec = timeout; limit.tv_usec = 0; rc = select(fdmax, &set, NULL, NULL, (0 != timeout && !paused) ? &limit : NULL); if (switch_last != fb_switch_state) { console_switch(); continue; } if (0 == rc) return KEY_TIMEOUT; if (FD_ISSET(0,&set)) { /* stdin, i.e. keyboard */ rc = read(0, key, sizeof(key)-1); if (rc < 1) { /* EOF */ return KEY_EOF; } key[rc] = 0; } #ifdef HAVE_LIBLIRC if (lirc != -1 && FD_ISSET(lirc,&set)) { /* lirc input */ if (-1 == lirc_fbi_havedata(&rc,key)) { fprintf(stderr,"lirc: connection lost\n"); close(lirc); lirc = -1; } key[rc] = 0; } #endif if (rc == 1 && (*key == 'q' || *key == 'Q' || *key == 'e' || *key == 'E' || *key == '\x1b' || *key == '\n')) { if (*key == '\n') return KEY_TAGFILE; if (*key == '\x1b') return KEY_ESC; return KEY_Q; } else if (0 == strcmp(key, " ")) { if (textreading && f->top < (int)(img->i.height - fb_var.yres)) { redraw = 1; f->top += f->text_steps; } else { skip = KEY_SPACE; return KEY_SPACE; } } else if (0 == strcmp(key, "\x1b[A") && img->i.height > fb_var.yres) { redraw = 1; f->top -= v_steps; } else if (0 == strcmp(key, "\x1b[B") && img->i.height > fb_var.yres) { redraw = 1; f->top += v_steps; } else if (0 == strcmp(key, "\x1b[1~") && img->i.height > fb_var.yres) { redraw = 1; f->top = 0; } else if (0 == strcmp(key, "\x1b[4~")) { redraw = 1; f->top = img->i.height - fb_var.yres; } else if (0 == strcmp(key, "\x1b[D") && img->i.width > fb_var.xres) { redraw = 1; f->left -= h_steps; } else if (0 == strcmp(key, "\x1b[C") && img->i.width > fb_var.xres) { redraw = 1; f->left += h_steps; } else if (0 == strcmp(key, "\x1b[5~") || 0 == strcmp(key, "k") || 0 == strcmp(key, "K")) { if (textreading && f->top > 0) { redraw = 1; f->top -= f->text_steps; } else { skip = KEY_PGUP; return KEY_PGUP; } } else if (0 == strcmp(key, "\x1b[6~") || 0 == strcmp(key, "j") || 0 == strcmp(key, "J") || 0 == strcmp(key, "n") || 0 == strcmp(key, "N")) { if (textreading && f->top < (int)(img->i.height - fb_var.yres)) { redraw = 1; f->top += f->text_steps; } else { skip = KEY_PGDN; return KEY_PGDN; } } else if (0 == strcmp(key, "+")) { return KEY_PLUS; } else if (0 == strcmp(key, "-")) { return KEY_MINUS; } else if (0 == strcmp(key, "a") || 0 == strcmp(key, "A")) { return KEY_ASCALE; } else if (0 == strcmp(key, "p") || 0 == strcmp(key, "P")) { if (0 != timeout) { paused = !paused; status_update(paused ? "pause on " : "pause off", NULL); } } else if (0 == strcmp(key, "D")) { return KEY_DELETE; } else if (0 == strcmp(key, "r") || 0 == strcmp(key, "R")) { return KEY_ROT_CW; } else if (0 == strcmp(key, "l") || 0 == strcmp(key, "L")) { return KEY_ROT_CCW; } else if (0 == strcmp(key, "x") || 0 == strcmp(key, "X")) { return KEY_FLIP_V; } else if (0 == strcmp(key, "y") || 0 == strcmp(key, "Y")) { return KEY_FLIP_H; } else if (0 == strcmp(key, "h") || 0 == strcmp(key, "H")) { if (!help) { show_help(); help = 1; } else { redraw = 1; help = 0; } exif = 0; } else if (0 == strcmp(key, "i") || 0 == strcmp(key, "I")) { if (!exif) { show_exif(fcurrent); exif = 1; } else { redraw = 1; exif = 0; } help = 0; } else if (0 == strcmp(key, "v") || 0 == strcmp(key, "V")) { return KEY_VERBOSE; } else if (0 == strcmp(key, "t") || 0 == strcmp(key, "T")) { return KEY_DESC; } else if (rc == 1 && (*key == 'g' || *key == 'G')) { return KEY_GOTO; } else if (rc == 1 && (*key == 's' || *key == 'S')) { return KEY_SCALE; } else if (rc == 1 && (*key == 'x' || *key == 'X')) { return KEY_DELAY; } else if (rc == 1 && *key >= '0' && *key <= '9') { *nr = *nr * 10 + (*key - '0'); snprintf(linebuffer, sizeof(linebuffer), "> %d",*nr); status_update(linebuffer, NULL); } else { *nr = 0; #if 0 debug_key(key); #endif } } } static void scale_fix_top_left(struct flist *f, float old, float new) { struct ida_image *img = flist_img_get(f); unsigned int width, height; float cx,cy; cx = (float)(f->left + fb_var.xres/2) / (img->i.width * old); cy = (float)(f->top + fb_var.yres/2) / (img->i.height * old); width = img->i.width * new; height = img->i.height * new; f->left = cx * width - fb_var.xres/2; f->top = cy * height - fb_var.yres/2; if (textreading) { f->text_steps = calculate_text_steps(height, fb_var.yres); } } /* ---------------------------------------------------------------------- */ static char *my_basename(char *filename) { char *h; h = strrchr(filename,'/'); if (h) return h+1; return filename; } static char *file_desktop(char *filename) { static char desc[128]; char *h; strncpy(desc,filename,sizeof(desc)-1); if (NULL != (h = strrchr(filename,'/'))) { snprintf(desc,sizeof(desc),"%.*s/%s", (int)(h - filename), filename, ".directory"); } else { strcpy(desc,".directory"); } return desc; } static char *make_desc(struct ida_image_info *img, char *filename) { static char linebuffer[128]; struct ida_extra *extra; char *desc; int len; memset(linebuffer,0,sizeof(linebuffer)); strncpy(linebuffer,filename,sizeof(linebuffer)-1); if (comments) { extra = load_find_extra(img, EXTRA_COMMENT); if (extra) snprintf(linebuffer,sizeof(linebuffer),"%.*s", extra->size,extra->data); } else { desc = file_desktop(filename); len = desktop_read_entry(desc, "Comment=", linebuffer, sizeof(linebuffer)); if (0 != len) snprintf(linebuffer+len,sizeof(linebuffer)-len, " (%s)", my_basename(filename)); } return linebuffer; } static char *make_info(struct ida_image *img, float scale) { static char linebuffer[128]; snprintf(linebuffer, sizeof(linebuffer), "%s%.0f%% %ux%u %d/%d", fcurrent->tag ? "* " : "", scale*100, img->i.width, img->i.height, fcurrent->nr, fcount); return linebuffer; } static char edit_line(struct ida_image *img, char *line, int max) { int len = strlen(line); int pos = len; int rc; char key[11]; fd_set set; do { status_edit(line,pos); FD_SET(0, &set); rc = select(1, &set, NULL, NULL, NULL); if (switch_last != fb_switch_state) { console_switch(); continue; } rc = read(0, key, sizeof(key)-1); if (rc < 1) { /* EOF */ return KEY_EOF; } key[rc] = 0; if (0 == strcmp(key,"\x0a")) { /* Enter */ return 0; } else if (0 == strcmp(key,"\x1b")) { /* ESC */ return KEY_ESC; } else if (0 == strcmp(key,"\x1b[C")) { /* cursor right */ if (pos < len) pos++; } else if (0 == strcmp(key,"\x1b[D")) { /* cursor left */ if (pos > 0) pos--; } else if (0 == strcmp(key,"\x1b[1~")) { /* home */ pos = 0; } else if (0 == strcmp(key,"\x1b[4~")) { /* end */ pos = len; } else if (0 == strcmp(key,"\x7f")) { /* backspace */ if (pos > 0) { memmove(line+pos-1,line+pos,len-pos+1); pos--; len--; } } else if (0 == strcmp(key,"\x1b[3~")) { /* delete */ if (pos < len) { memmove(line+pos,line+pos+1,len-pos); len--; } } else if (1 == rc && isprint(key[0]) && len < max) { /* new key */ if (pos < len) memmove(line+pos+1,line+pos,len-pos+1); line[pos] = key[0]; pos++; len++; line[len] = 0; } else if (0 /* debug */) { debug_key(key); sleep(1); } } while (1); } static void edit_desc(struct ida_image *img, char *filename) { static char linebuffer[128]; char *desc; int len, rc; desc = file_desktop(filename); len = desktop_read_entry(desc, "Comment=", linebuffer, sizeof(linebuffer)); if (0 == len) { linebuffer[0] = 0; len = 0; } rc = edit_line(img, linebuffer, sizeof(linebuffer)-1); if (0 != rc) return; desktop_write_entry(desc, "Directory", "Comment=", linebuffer); } /* ---------------------------------------------------------------------- */ static struct ida_image *flist_img_get(struct flist *f) { if (1 != f->scale) return f->simg; else return f->fimg; } static void flist_img_free(struct flist *f) { if (!f->fimg) return; free_image(f->fimg); if (f->simg) free_image(f->simg); f->fimg = NULL; f->simg = NULL; list_del(&f->lru); img_cnt--; } static int flist_img_free_lru(void) { struct flist *f; if (img_cnt <= min_cnt) return -1; f = list_entry(flru.next, struct flist, lru); flist_img_free(f); return 0; } static void flist_img_release_memory(void) { int try_release; for (;;) { try_release = 0; if (img_cnt > max_cnt) try_release = 1; if (img_mem > max_mem_mb * 1024 * 1024) try_release = 1; if (!try_release) break; if (0 != flist_img_free_lru()) break; } return; } static void *flist_malloc(size_t size) { void *ptr; for (;;) { ptr = malloc(size); if (ptr) return ptr; if (0 != flist_img_free_lru()) { status_error("Oops: out of memory, exiting"); exit(1); } } } static void flist_img_scale(struct flist *f, float scale, int prefetch) { char linebuffer[128]; if (!f->fimg) return; if (f->simg && f->scale == scale) return; if (f->simg) { free_image(f->simg); f->simg = NULL; } if (scale != 1) { if (!prefetch) { snprintf(linebuffer, sizeof(linebuffer), "scaling (%.0f%%) %s ...", scale*100, f->name); status_update(linebuffer, NULL); } f->simg = scale_image(f->fimg,scale); if (!f->simg) { snprintf(linebuffer,sizeof(linebuffer), "%s: scaling FAILED",f->name); status_error(linebuffer); } } f->scale = scale; } static void flist_img_load(struct flist *f, int prefetch) { char linebuffer[128]; float scale = 1; if (f->fimg) { /* touch */ list_del(&f->lru); list_add_tail(&f->lru, &flru); return; } snprintf(linebuffer,sizeof(linebuffer),"%s %s ...", prefetch ? "prefetch" : "loading", f->name); status_update(linebuffer, NULL); f->fimg = read_image(f->name); if (!f->fimg) { snprintf(linebuffer,sizeof(linebuffer), "%s: loading FAILED",f->name); status_error(linebuffer); return; } if (!f->seen) { scale = 1; if (autoup || autodown) { scale = auto_scale(f->fimg); if (scale < 1 && !autodown) scale = 1; if (scale > 1 && !autoup) scale = 1; } } else { scale = f->scale; } flist_img_scale(f, scale, prefetch); if (!f->seen) { struct ida_image *img = flist_img_get(f); if (img->i.width > fb_var.xres) f->left = (img->i.width - fb_var.xres) / 2; if (img->i.height > fb_var.yres) { f->top = (img->i.height - fb_var.yres) / 2; if (textreading) { f->text_steps = calculate_text_steps(img->i.height, fb_var.yres); f->top = 0; } } } list_add_tail(&f->lru, &flru); f->seen = 1; img_cnt++; } /* ---------------------------------------------------------------------- */ static void cleanup_and_exit(int code) { shadow_fini(); fb_clear_screen(); tty_restore(); fb_cleanup(); flist_print_tagged(stdout); exit(code); } int main(int argc, char *argv[]) { int once; int i, arg, key; char *info, *desc, *filelist; char linebuffer[128]; struct flist *fprev = NULL; #if 0 /* debug aid, to attach gdb ... */ fprintf(stderr,"pid %d\n",getpid()); sleep(10); #endif setlocale(LC_ALL,""); #ifdef HAVE_LIBLIRC lirc = lirc_fbi_init(); #endif fbi_read_config(); cfg_parse_cmdline(&argc,argv,fbi_cmd); cfg_parse_cmdline(&argc,argv,fbi_cfg); if (GET_AUTO_ZOOM()) { cfg_set_bool(O_AUTO_UP, 1); cfg_set_bool(O_AUTO_DOWN, 1); } if (GET_HELP()) { usage(argv[0]); exit(0); } if (GET_VERSION()) { version(); exit(0); } if (GET_WRITECONF()) fbi_write_config(); once = GET_ONCE(); autoup = GET_AUTO_UP(); autodown = GET_AUTO_DOWN(); fitwidth = GET_FIT_WIDTH(); statusline = GET_VERBOSE(); textreading = GET_TEXT_MODE(); editable = GET_EDIT(); backup = GET_BACKUP(); preserve = GET_PRESERVE(); read_ahead = GET_READ_AHEAD(); max_mem_mb = GET_CACHE_MEM(); blend_msecs = GET_BLEND_MSECS(); v_steps = GET_SCROLL(); h_steps = GET_SCROLL(); timeout = GET_TIMEOUT(); pcd_res = GET_PCD_RES(); fbgamma = GET_GAMMA(); fontname = cfg_get_str(O_FONT); filelist = cfg_get_str(O_FILE_LIST); if (filelist) flist_add_list(filelist); for (i = optind; i < argc; i++) flist_add(argv[i]); flist_renumber(); if (0 == fcount) { usage(argv[0]); exit(1); } if (GET_RANDOM()) flist_randomize(); fcurrent = flist_first(); font_init(); if (NULL == fontname) fontname = "monospace:size=16"; face = font_open(fontname); if (NULL == face) { fprintf(stderr,"can't open font: %s\n",fontname); exit(1); } fd = fb_init(cfg_get_str(O_DEVICE), cfg_get_str(O_VIDEO_MODE), GET_VT()); fb_catch_exit_signals(); fb_switch_init(); shadow_init(); shadow_set_palette(fd); signal(SIGTSTP,SIG_IGN); /* svga main loop */ tty_raw(); desc = NULL; info = NULL; for (;;) { flist_img_load(fcurrent, 0); flist_img_release_memory(); img = flist_img_get(fcurrent); if (img) { desc = make_desc(&fcurrent->fimg->i, fcurrent->name); info = make_info(fcurrent->fimg, fcurrent->scale); } key = svga_show(fcurrent, fprev, timeout, desc, info, &arg); fprev = fcurrent; switch (key) { case KEY_DELETE: if (editable) { struct flist *fdel = fcurrent; if (flist_islast(fcurrent)) fcurrent = flist_prev(fcurrent,0); else fcurrent = flist_next(fcurrent,0,0); unlink(fdel->name); flist_img_free(fdel); flist_del(fdel); flist_renumber(); if (list_empty(&flist)) { /* deleted last one */ cleanup_and_exit(0); } } else { status_error("readonly mode, sorry [start with --edit?]"); } break; case KEY_ROT_CW: case KEY_ROT_CCW: { if (editable) { snprintf(linebuffer,sizeof(linebuffer), "rotating %s ...",fcurrent->name); status_update(linebuffer, NULL); jpeg_transform_inplace (fcurrent->name, (key == KEY_ROT_CW) ? JXFORM_ROT_90 : JXFORM_ROT_270, NULL, NULL,0, (backup ? JFLAG_FILE_BACKUP : 0) | (preserve ? JFLAG_FILE_KEEP_TIME : 0) | JFLAG_TRANSFORM_IMAGE | JFLAG_TRANSFORM_THUMBNAIL | JFLAG_TRANSFORM_TRIM | JFLAG_UPDATE_ORIENTATION); flist_img_free(fcurrent); } else { status_error("readonly mode, sorry [start with --edit?]"); } break; } case KEY_FLIP_V: case KEY_FLIP_H: { if (editable) { snprintf(linebuffer,sizeof(linebuffer), "mirroring %s ...",fcurrent->name); status_update(linebuffer, NULL); jpeg_transform_inplace (fcurrent->name, (key == KEY_FLIP_V) ? JXFORM_FLIP_V : JXFORM_FLIP_H, NULL, NULL,0, (backup ? JFLAG_FILE_BACKUP : 0) | (preserve ? JFLAG_FILE_KEEP_TIME : 0) | JFLAG_TRANSFORM_IMAGE | JFLAG_TRANSFORM_THUMBNAIL | JFLAG_TRANSFORM_TRIM | JFLAG_UPDATE_ORIENTATION); flist_img_free(fcurrent); } else { status_error("readonly mode, sorry [start with --edit?]"); } break; } case KEY_TAGFILE: fcurrent->tag = !fcurrent->tag; /* fall throuth */ case KEY_SPACE: fcurrent = flist_next(fcurrent,1,0); if (NULL != fcurrent) break; /* else fall */ case KEY_ESC: case KEY_Q: case KEY_EOF: cleanup_and_exit(0); break; case KEY_PGDN: fcurrent = flist_next(fcurrent,0,1); break; case KEY_PGUP: fcurrent = flist_prev(fcurrent,1); break; case KEY_TIMEOUT: fcurrent = flist_next(fcurrent,once,1); if (NULL == fcurrent) { cleanup_and_exit(0); } /* FIXME: wrap around */ break; case KEY_PLUS: case KEY_MINUS: case KEY_ASCALE: case KEY_SCALE: { float newscale, oldscale = fcurrent->scale; if (key == KEY_PLUS) { newscale = fcurrent->scale * 1.6; } else if (key == KEY_MINUS) { newscale = fcurrent->scale / 1.6; } else if (key == KEY_ASCALE) { newscale = auto_scale(fcurrent->fimg); } else { newscale = arg / 100.0; } if (newscale < 0.1) newscale = 0.1; if (newscale > 10) newscale = 10; flist_img_scale(fcurrent, newscale, 0); scale_fix_top_left(fcurrent, oldscale, newscale); break; } case KEY_GOTO: if (arg > 0 && arg <= fcount) fcurrent = flist_goto(arg); break; case KEY_DELAY: timeout = arg; break; case KEY_VERBOSE: #if 0 /* fbdev testing/debugging hack */ { ioctl(fd,FBIOBLANK,1); sleep(1); ioctl(fd,FBIOBLANK,0); } #endif statusline = !statusline; break; case KEY_DESC: if (!comments) { edit_desc(img, fcurrent->name); desc = make_desc(&fcurrent->fimg->i,fcurrent->name); } break; } } } fbi-2.10/ida.c0000644000175000017500000015103512506525033011233 0ustar jmmjmm#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "RegEdit.h" #include "ida.h" #include "x11.h" #include "man.h" #include "readers.h" #include "writers.h" #include "viewer.h" #include "op.h" #include "lut.h" #include "filter.h" #include "color.h" #include "icons.h" #include "browser.h" #include "filelist.h" #include "xdnd.h" #include "selections.h" #include "sane.h" #include "curl.h" #include "idaconfig.h" /* ---------------------------------------------------------------------- */ static void popup_ac(Widget, XEvent*, String*, Cardinal*); static void exit_ac(Widget, XEvent*, String*, Cardinal*); static void next_ac(Widget, XEvent*, String*, Cardinal*); static void prev_ac(Widget, XEvent*, String*, Cardinal*); static void next_page_ac(Widget, XEvent*, String*, Cardinal*); static void prev_page_ac(Widget, XEvent*, String*, Cardinal*); static void zoom_ac(Widget, XEvent*, String*, Cardinal*); static void scroll_ac(Widget, XEvent*, String*, Cardinal*); static void debug_ac(Widget, XEvent*, String*, Cardinal*); static void load_ac(Widget, XEvent*, String*, Cardinal*); static void save_ac(Widget, XEvent*, String*, Cardinal*); static void scan_ac(Widget, XEvent*, String*, Cardinal*); static void print_ac(Widget, XEvent*, String*, Cardinal*); static void undo_ac(Widget, XEvent*, String*, Cardinal*); static void filter_ac(Widget, XEvent*, String*, Cardinal*); static void gamma_ac(Widget, XEvent*, String*, Cardinal*); static void bright_ac(Widget, XEvent*, String*, Cardinal*); static void contrast_ac(Widget, XEvent*, String*, Cardinal*); static void color_ac(Widget, XEvent*, String*, Cardinal*); static void f3x3_ac(Widget, XEvent*, String*, Cardinal*); static void resize_ac(Widget, XEvent*, String*, Cardinal*); static void rotate_ac(Widget, XEvent*, String*, Cardinal*); static void sharpe_ac(Widget, XEvent*, String*, Cardinal*); static XtActionsRec actionTable[] = { { "Exit", exit_ac }, { "Next", next_ac }, { "Prev", prev_ac }, { "NextPage", next_page_ac }, { "PrevPage", prev_page_ac }, { "Zoom", zoom_ac }, { "Scroll", scroll_ac }, { "Debug", debug_ac }, { "Popup", popup_ac }, { "Man", man_action }, { "Load", load_ac }, { "Save", save_ac }, { "Scan", scan_ac }, { "Print", print_ac }, { "Browser", browser_ac }, { "Filelist", filelist_ac }, { "Undo", undo_ac }, { "Filter", filter_ac }, { "Gamma", gamma_ac }, { "Bright", bright_ac }, { "Contrast", contrast_ac }, { "Color", color_ac }, { "F3x3", f3x3_ac }, { "Resize", resize_ac }, { "Rotate", rotate_ac }, { "Sharpe", sharpe_ac }, { "Ipc", ipc_ac }, { "Xdnd", XdndAction }, }; /* ---------------------------------------------------------------------- */ XtAppContext app_context; Display *dpy; Widget app_shell; int gray=0; char *binary; struct ida_viewer *ida; /* ---------------------------------------------------------------------- */ struct ARGS args; unsigned int pcd_res; unsigned int sane_res; XtResource args_desc[] = { { "debug", XtCBoolean, XtRBoolean, sizeof(Boolean), XtOffset(struct ARGS*,debug), XtRString, "false" },{ "help", XtCBoolean, XtRBoolean, sizeof(Boolean), XtOffset(struct ARGS*,help), XtRString, "false" },{ "testload", XtCBoolean, XtRBoolean, sizeof(Boolean), XtOffset(struct ARGS*,testload), XtRString, "false" } }; const int args_count = XtNumber(args_desc); XrmOptionDescRec opt_desc[] = { { "-d", "debug", XrmoptionNoArg, "true" }, { "-debug", "debug", XrmoptionNoArg, "true" }, { "-testload", "testload", XrmoptionNoArg, "true" }, { "-h", "help", XrmoptionNoArg, "true" }, { "-help", "help", XrmoptionNoArg, "true" }, { "--help", "help", XrmoptionNoArg, "true" }, }; const int opt_count = (sizeof(opt_desc)/sizeof(XrmOptionDescRec)); static String fallback_ressources[] = { #include "Ida.ad.h" NULL }; /* ---------------------------------------------------------------------- */ static struct ida_writer *cwriter; static char *save_filename; static char *print_command; static Widget control_shell,status; static Atom wm_delete_window; static Widget view,loadbox,savebox,printbox; /* file list */ static Widget wlist; static char **files = NULL; static int cfile = -1; static int nfiles = 0; static int cpage = 0; static int npages = 1; /* filter controls */ static int gamma_val = 100; static int bright_val = 0; static int contrast_val = 0; static int rotate_val = 0; static int sharpe_val = 10; static struct MY_TOPLEVELS { char *name; Widget *shell; int mapped; } my_toplevels [] = { { "control", &control_shell }, }; #define TOPLEVELS (sizeof(my_toplevels)/sizeof(struct MY_TOPLEVELS)) /* ---------------------------------------------------------------------- */ static void popup_ac(Widget widget, XEvent *event, String *params, Cardinal *num_params) { unsigned int i; /* which window we are talking about ? */ if (*num_params > 0) { for (i = 0; i < TOPLEVELS; i++) { if (0 == strcasecmp(my_toplevels[i].name,params[0])) break; } if (i == TOPLEVELS) { fprintf(stderr,"PopupAction: oops: shell not found (name=%s)\n", params[0]); return; } } else { for (i = 0; i < TOPLEVELS; i++) { if (*(my_toplevels[i].shell) == widget) break; } if (i == TOPLEVELS) { fprintf(stderr,"PopupAction: oops: shell not found (%p:%s)\n", widget,XtName(widget)); return; } } /* popup/down window */ if (!my_toplevels[i].mapped) { XtPopup(*(my_toplevels[i].shell), XtGrabNone); my_toplevels[i].mapped = 1; } else { XtPopdown(*(my_toplevels[i].shell)); my_toplevels[i].mapped = 0; } } static void popupdown_cb(Widget widget, XtPointer clientdata, XtPointer call_data) { int i = 0; popup_ac(clientdata, NULL, NULL, &i); } /* ---------------------------------------------------------------------- */ void destroy_cb(Widget widget, XtPointer clientdata, XtPointer call_data) { XtDestroyWidget(clientdata); } void action_cb(Widget widget, XtPointer clientdata, XtPointer call_data) { char *calls, *action, *argv[16]; /* max: F3x3(9 args) */ int argc; calls = strdup(clientdata); action = strtok(calls,"(),"); for (argc = 0; NULL != (argv[argc] = strtok(NULL,"(),")); argc++) /* nothing */; XtCallActionProc(widget,action,NULL,argv,argc); free(calls); } static void about_cb(Widget widget, XtPointer clientdata, XtPointer call_data) { Widget msgbox; msgbox = XmCreateInformationDialog(app_shell,"aboutbox",NULL,0); XtUnmanageChild(XmMessageBoxGetChild(msgbox,XmDIALOG_HELP_BUTTON)); XtUnmanageChild(XmMessageBoxGetChild(msgbox,XmDIALOG_CANCEL_BUTTON)); XtAddCallback(msgbox,XmNokCallback,destroy_cb,msgbox); XtManageChild(msgbox); } #if 0 static void sorry_cb(Widget widget, XtPointer clientdata, XtPointer call_data) { Widget msgbox; msgbox = XmCreateErrorDialog(app_shell,"sorrybox",NULL,0); XtUnmanageChild(XmMessageBoxGetChild(msgbox,XmDIALOG_HELP_BUTTON)); XtUnmanageChild(XmMessageBoxGetChild(msgbox,XmDIALOG_CANCEL_BUTTON)); XtAddCallback(msgbox,XmNokCallback,destroy_cb,msgbox); XtManageChild(msgbox); } #endif void debug_ac(Widget widget, XEvent *event, String *params, Cardinal *num) { unsigned int i; fprintf(stderr,"Debug:"); for (i = 0; i < *num; i++) fprintf(stderr," %s",params[i]); fprintf(stderr,"\n"); } static void display_cb(Widget widget, XtPointer clientdata, XtPointer call_data) { XmDisplayCallbackStruct *arg = call_data; switch (arg->reason) { case XmCR_NO_RENDITION: fprintf(stderr,"display_cb: no rendition: \"%s\"\n",arg->tag); break; case XmCR_NO_FONT: fprintf(stderr,"display_cb: no font: \"%s\"\n",arg->font_name); break; default: /* should not happen */ fprintf(stderr,"display_cb: unknown reason [%d]\n",arg->reason); break; } } /* ---------------------------------------------------------------------- */ struct ptr_list { struct ptr_list *next; Widget widget; }; struct ptr_list *ptr_head; void ptr_register(Widget widget) { struct ptr_list *item; if (XtWindow(widget)) XDefineCursor(XtDisplay(widget), XtWindow(widget), ptrs[POINTER_NORMAL]); item = malloc(sizeof(*item)); memset(item,0,sizeof(*item)); item->widget = widget; item->next = ptr_head; ptr_head = item; } void ptr_unregister(Widget widget) { struct ptr_list *item,*fitem; if (ptr_head->widget == widget) { fitem = ptr_head; ptr_head = ptr_head->next; free(fitem); return; } for (item = ptr_head; NULL != item->next; item = item->next) { if (item->next->widget == widget) { fitem = item->next; item->next = fitem->next; free(fitem); return; } } /* shouldn't happen */ fprintf(stderr,"Oops: widget not found in list\n"); } void ptr_busy(void) { struct ptr_list *item; for (item = ptr_head; NULL != item; item = item->next) { if (!XtWindow(item->widget)) continue; XDefineCursor(XtDisplay(item->widget), XtWindow(item->widget), ptrs[POINTER_BUSY]); } XSync(dpy,False); } void ptr_idle(void) { struct ptr_list *item; for (item = ptr_head; NULL != item; item = item->next) { if (!XtWindow(item->widget)) continue; XDefineCursor(XtDisplay(item->widget), XtWindow(item->widget), ptrs[POINTER_NORMAL]); } } /* ---------------------------------------------------------------------- */ static Boolean exit_wp(XtPointer client_data) { exit(0); } static void exit_cb(Widget widget, XtPointer client_data, XtPointer calldata) { XtAppAddWorkProc(app_context,exit_wp, NULL); XtDestroyWidget(app_shell); } void exit_ac(Widget widget, XEvent *event, String *params, Cardinal *num) { exit_cb(widget,NULL,NULL); } /* ---------------------------------------------------------------------- */ static void list_update(void) { XmStringTable tab; int i; tab = malloc(nfiles * sizeof(XmString)); for (i = 0; i < nfiles; i++) tab[i] = XmStringGenerate(files[i], NULL, XmMULTIBYTE_TEXT, NULL); XtVaSetValues(wlist, XmNitems, tab, XmNitemCount, nfiles, NULL); for (i = 0; i < nfiles; i++) XmStringFree(tab[i]); free(tab); } static int list_append(char *filename) { int i; for (i = 0; i < nfiles; i++) if (0 == strcmp(files[i],filename)) return i; files = realloc(files,sizeof(char*)*(nfiles+1)); files[nfiles] = strdup(filename); nfiles++; return nfiles-1; } static void list_cb(Widget widget, XtPointer client_data, XtPointer calldata) { XmListCallbackStruct *list = calldata; if (0 == list->selected_item_count) return; cfile = list->selected_item_positions[0]-1; cpage = 0; npages = viewer_loadimage(ida,files[cfile],cpage); if (-1 == npages) return; resize_shell(); } static void pcd_set(Widget widget) { WidgetList items; Cardinal nitems; unsigned int i; int value; value = GET_PHOTOCD_RES(); XtVaGetValues(widget,XtNchildren,&items, XtNnumChildren,&nitems,NULL); for (i = 0; i < nitems; i++) XmToggleButtonSetState(items[i],value == i+1,False); pcd_res = value; } static void pcd_cb(Widget widget, XtPointer client_data, XtPointer calldata) { cfg_set_int(O_PHOTOCD_RES,(intptr_t)client_data); pcd_set(XtParent(widget)); } static void cfg_bool_cb(Widget widget, XtPointer client_data, XtPointer calldata) { char *option = XtName(widget); Boolean value = XmToggleButtonGetState(widget); cfg_set_bool(O_OPTIONS, option, value); } static void cfg_save_cb(Widget widget, XtPointer client_data, XtPointer calldata) { ida_write_config(); } static void create_control(void) { Widget form,menubar,tool,menu,smenu,push; control_shell = XtVaAppCreateShell("ctrl","Iv", topLevelShellWidgetClass, dpy, XtNclientLeader,app_shell, XmNdeleteResponse,XmDO_NOTHING, NULL); XmdRegisterEditres(control_shell); XmAddWMProtocolCallback(control_shell,wm_delete_window, popupdown_cb,control_shell); /* widgets */ form = XtVaCreateManagedWidget("form", xmFormWidgetClass, control_shell, NULL); menubar = XmCreateMenuBar(form,"bar",NULL,0); XtManageChild(menubar); tool = XtVaCreateManagedWidget("tool",xmRowColumnWidgetClass, form, NULL); status = XtVaCreateManagedWidget("status", xmLabelWidgetClass, form, NULL); wlist = XmCreateScrolledList(form,"list",NULL,0); XtManageChild(wlist); XtAddCallback(wlist,XmNdefaultActionCallback,list_cb,NULL); XtAddCallback(wlist,XmNdestinationCallback,selection_dest,NULL); dnd_add(wlist); /* menu - file */ menu = XmCreatePulldownMenu(menubar,"fileM",NULL,0); XtVaCreateManagedWidget("file",xmCascadeButtonWidgetClass,menubar, XmNsubMenuId,menu,NULL); push = XtVaCreateManagedWidget("load",xmPushButtonWidgetClass,menu,NULL); XtAddCallback(push,XmNactivateCallback,action_cb,"Load()"); push = XtVaCreateManagedWidget("save",xmPushButtonWidgetClass,menu,NULL); XtAddCallback(push,XmNactivateCallback,action_cb,"Save()"); push = XtVaCreateManagedWidget("browse",xmPushButtonWidgetClass,menu,NULL); XtAddCallback(push,XmNactivateCallback,action_cb,"Browser()"); push = XtVaCreateManagedWidget("filelist",xmPushButtonWidgetClass,menu,NULL); XtAddCallback(push,XmNactivateCallback,action_cb,"Filelist()"); XtVaCreateManagedWidget("sep",xmSeparatorWidgetClass,menu,NULL); #ifdef HAVE_LIBSANE sane_menu(menu); #endif push = XtVaCreateManagedWidget("print",xmPushButtonWidgetClass,menu,NULL); XtAddCallback(push,XmNactivateCallback,action_cb,"Print()"); XtVaCreateManagedWidget("sep",xmSeparatorWidgetClass,menu,NULL); push = XtVaCreateManagedWidget("quit",xmPushButtonWidgetClass,menu,NULL); XtAddCallback(push,XmNactivateCallback,exit_cb,NULL); /* menu - edit */ menu = XmCreatePulldownMenu(menubar,"editM",NULL,0); XtVaCreateManagedWidget("edit",xmCascadeButtonWidgetClass,menubar, XmNsubMenuId,menu,NULL); push = XtVaCreateManagedWidget("undo",xmPushButtonWidgetClass,menu,NULL); XtAddCallback(push,XmNactivateCallback,action_cb,"Undo()"); XtVaCreateManagedWidget("sep",xmSeparatorWidgetClass,menu,NULL); push = XtVaCreateManagedWidget("copy",xmPushButtonWidgetClass,menu,NULL); XtAddCallback(push,XmNactivateCallback,action_cb,"Ipc(copy)"); push = XtVaCreateManagedWidget("paste",xmPushButtonWidgetClass,menu,NULL); XtAddCallback(push,XmNactivateCallback,action_cb,"Ipc(paste)"); XtVaCreateManagedWidget("sep",xmSeparatorWidgetClass,menu,NULL); push = XtVaCreateManagedWidget("flipv",xmPushButtonWidgetClass,menu,NULL); XtAddCallback(push,XmNactivateCallback,action_cb,"Filter(flip-vert)"); push = XtVaCreateManagedWidget("fliph",xmPushButtonWidgetClass,menu,NULL); XtAddCallback(push,XmNactivateCallback,action_cb,"Filter(flip-horz)"); push = XtVaCreateManagedWidget("rotcw",xmPushButtonWidgetClass,menu,NULL); XtAddCallback(push,XmNactivateCallback,action_cb,"Filter(rotate-cw)"); push = XtVaCreateManagedWidget("rotccw",xmPushButtonWidgetClass,menu,NULL); XtAddCallback(push,XmNactivateCallback,action_cb,"Filter(rotate-ccw)"); push = XtVaCreateManagedWidget("invert",xmPushButtonWidgetClass,menu,NULL); XtAddCallback(push,XmNactivateCallback,action_cb,"Filter(invert)"); XtVaCreateManagedWidget("sep",xmSeparatorWidgetClass,menu,NULL); push = XtVaCreateManagedWidget("crop",xmPushButtonWidgetClass,menu,NULL); XtAddCallback(push,XmNactivateCallback,action_cb,"Filter(crop)"); push = XtVaCreateManagedWidget("acrop",xmPushButtonWidgetClass,menu,NULL); XtAddCallback(push,XmNactivateCallback,action_cb,"Filter(autocrop)"); push = XtVaCreateManagedWidget("scale",xmPushButtonWidgetClass,menu,NULL); XtAddCallback(push,XmNactivateCallback,action_cb,"Resize()"); push = XtVaCreateManagedWidget("rotany",xmPushButtonWidgetClass,menu,NULL); XtAddCallback(push,XmNactivateCallback,action_cb,"Rotate()"); /* menu - filters / operations */ menu = XmCreatePulldownMenu(menubar,"opM",NULL,0); XtVaCreateManagedWidget("op",xmCascadeButtonWidgetClass,menubar, XmNsubMenuId,menu,NULL); push = XtVaCreateManagedWidget("gamma",xmPushButtonWidgetClass,menu,NULL); XtAddCallback(push,XmNactivateCallback,action_cb,"Gamma()"); push = XtVaCreateManagedWidget("bright",xmPushButtonWidgetClass,menu,NULL); XtAddCallback(push,XmNactivateCallback,action_cb,"Bright()"); push = XtVaCreateManagedWidget("contr",xmPushButtonWidgetClass,menu,NULL); XtAddCallback(push,XmNactivateCallback,action_cb,"Contrast()"); push = XtVaCreateManagedWidget("color",xmPushButtonWidgetClass,menu,NULL); XtAddCallback(push,XmNactivateCallback,action_cb,"Color()"); push = XtVaCreateManagedWidget("gray",xmPushButtonWidgetClass,menu,NULL); XtAddCallback(push,XmNactivateCallback,action_cb,"Filter(grayscale)"); XtVaCreateManagedWidget("sep",xmSeparatorWidgetClass,menu,NULL); push = XtVaCreateManagedWidget("blur",xmPushButtonWidgetClass,menu,NULL); XtAddCallback(push,XmNactivateCallback,action_cb, "F3x3(1,1,1, 1,1,1, 1,1,1, 1,9,0)"); push = XtVaCreateManagedWidget("sharpe",xmPushButtonWidgetClass,menu,NULL); XtAddCallback(push,XmNactivateCallback,action_cb,"Sharpe()"); push = XtVaCreateManagedWidget("edge",xmPushButtonWidgetClass,menu,NULL); XtAddCallback(push,XmNactivateCallback,action_cb, "F3x3(-1,-1,-1, -1,8,-1, -1,-1,-1)"); push = XtVaCreateManagedWidget("emboss",xmPushButtonWidgetClass,menu,NULL); XtAddCallback(push,XmNactivateCallback,action_cb, "F3x3(1,0,0, 0,0,0, 0,0,-1, 0,0,128)"); /* menu - view */ menu = XmCreatePulldownMenu(menubar,"viewM",NULL,0); XtVaCreateManagedWidget("view",xmCascadeButtonWidgetClass,menubar, XmNsubMenuId,menu,NULL); push = XtVaCreateManagedWidget("prev",xmPushButtonWidgetClass,menu,NULL); XtAddCallback(push,XmNactivateCallback,action_cb,"Prev()"); push = XtVaCreateManagedWidget("next",xmPushButtonWidgetClass,menu,NULL); XtAddCallback(push,XmNactivateCallback,action_cb,"Next()"); XtVaCreateManagedWidget("sep",xmSeparatorWidgetClass,menu,NULL); push = XtVaCreateManagedWidget("prevpage",xmPushButtonWidgetClass,menu,NULL); XtAddCallback(push,XmNactivateCallback,action_cb,"PrevPage()"); push = XtVaCreateManagedWidget("nextpage",xmPushButtonWidgetClass,menu,NULL); XtAddCallback(push,XmNactivateCallback,action_cb,"NextPage()"); XtVaCreateManagedWidget("sep",xmSeparatorWidgetClass,menu,NULL); push = XtVaCreateManagedWidget("zoomin",xmPushButtonWidgetClass,menu,NULL); XtAddCallback(push,XmNactivateCallback,action_cb,"Zoom(inc)"); push = XtVaCreateManagedWidget("zoomout",xmPushButtonWidgetClass,menu,NULL); XtAddCallback(push,XmNactivateCallback,action_cb,"Zoom(dec)"); /* menu - options */ menu = XmCreatePulldownMenu(menubar,"optM",NULL,0); push = XtVaCreateManagedWidget("opt",xmCascadeButtonWidgetClass,menubar, XmNsubMenuId,menu,NULL); smenu = XmCreatePulldownMenu(menu,"pcdM",NULL,0); XtVaCreateManagedWidget("pcd",xmCascadeButtonWidgetClass,menu, XmNsubMenuId,smenu,NULL); push = XtVaCreateManagedWidget("1",xmToggleButtonWidgetClass,smenu,NULL); XtAddCallback(push,XmNvalueChangedCallback,pcd_cb,(XtPointer)1); push = XtVaCreateManagedWidget("2",xmToggleButtonWidgetClass,smenu,NULL); XtAddCallback(push,XmNvalueChangedCallback,pcd_cb,(XtPointer)2); push = XtVaCreateManagedWidget("3",xmToggleButtonWidgetClass,smenu,NULL); XtAddCallback(push,XmNvalueChangedCallback,pcd_cb,(XtPointer)3); push = XtVaCreateManagedWidget("4",xmToggleButtonWidgetClass,smenu,NULL); XtAddCallback(push,XmNvalueChangedCallback,pcd_cb,(XtPointer)4); push = XtVaCreateManagedWidget("5",xmToggleButtonWidgetClass,smenu,NULL); XtAddCallback(push,XmNvalueChangedCallback,pcd_cb,(XtPointer)5); pcd_set(smenu); push = XtVaCreateManagedWidget("autozoom",xmToggleButtonWidgetClass,menu,NULL); XtAddCallback(push,XmNvalueChangedCallback,cfg_bool_cb,NULL); XmToggleButtonSetState(push,GET_AUTOZOOM(),False); XtVaCreateManagedWidget("sep",xmSeparatorWidgetClass,menu,NULL); push = XtVaCreateManagedWidget("cfgsave",xmPushButtonWidgetClass,menu,NULL); XtAddCallback(push,XmNactivateCallback,cfg_save_cb,NULL); /* menu - help */ menu = XmCreatePulldownMenu(menubar,"helpM",NULL,0); push = XtVaCreateManagedWidget("help",xmCascadeButtonWidgetClass,menubar, XmNsubMenuId,menu,NULL); XtVaSetValues(menubar,XmNmenuHelpWidget,push,NULL); push = XtVaCreateManagedWidget("man",xmPushButtonWidgetClass,menu,NULL); XtAddCallback(push,XmNactivateCallback,action_cb,"Man(ida)"); XtVaCreateManagedWidget("sep",xmSeparatorWidgetClass,menu,NULL); push = XtVaCreateManagedWidget("about",xmPushButtonWidgetClass,menu,NULL); XtAddCallback(push,XmNactivateCallback,about_cb,NULL); /* toolbar */ push = XtVaCreateManagedWidget("prev",xmPushButtonWidgetClass,tool,NULL); XtAddCallback(push,XmNactivateCallback,action_cb,"Prev()"); push = XtVaCreateManagedWidget("next",xmPushButtonWidgetClass,tool,NULL); XtAddCallback(push,XmNactivateCallback,action_cb,"Next()"); push = XtVaCreateManagedWidget("zoomin",xmPushButtonWidgetClass,tool,NULL); XtAddCallback(push,XmNactivateCallback,action_cb,"Zoom(inc)"); push = XtVaCreateManagedWidget("zoomout",xmPushButtonWidgetClass,tool,NULL); XtAddCallback(push,XmNactivateCallback,action_cb,"Zoom(dec)"); XtVaCreateManagedWidget("sep",xmSeparatorWidgetClass,tool,NULL); push = XtVaCreateManagedWidget("flipv",xmPushButtonWidgetClass,tool,NULL); XtAddCallback(push,XmNactivateCallback,action_cb,"Filter(flip-vert)"); push = XtVaCreateManagedWidget("fliph",xmPushButtonWidgetClass,tool,NULL); XtAddCallback(push,XmNactivateCallback,action_cb,"Filter(flip-horz)"); push = XtVaCreateManagedWidget("rotccw",xmPushButtonWidgetClass,tool,NULL); XtAddCallback(push,XmNactivateCallback,action_cb,"Filter(rotate-ccw)"); push = XtVaCreateManagedWidget("rotcw",xmPushButtonWidgetClass,tool,NULL); XtAddCallback(push,XmNactivateCallback,action_cb,"Filter(rotate-cw)"); XtVaCreateManagedWidget("sep",xmSeparatorWidgetClass,tool,NULL); push = XtVaCreateManagedWidget("exit",xmPushButtonWidgetClass,tool,NULL); XtAddCallback(push,XmNactivateCallback,exit_cb,NULL); } /* ---------------------------------------------------------------------- */ void resize_shell(void) { char *title,*base; Dimension x,y,w,h,sw,sh; XmString str; int len; XtVaGetValues(app_shell, XtNx,&x, XtNy,&y, NULL); /* resize shell + move shell size: image size + 2*shadowThickness */ w = ida->scrwidth+2; h = ida->scrheight+2; sw = XtScreen(ida->widget)->width; sh = XtScreen(ida->widget)->height; if (w > sw) w = sw; if (h > sh) h = sh; if (x+w > sw) x = sw-w; if (y+h > sh) y = sh-h; base = strrchr(ida->file,'/'); if (base) base++; else base = ida->file; title = malloc(strlen(base)+128); len = sprintf(title,"%s (%ux%u", base, ida->img.i.width, ida->img.i.height); if (ida->img.i.dpi) len += sprintf(title+len," | %u dpi", ida->img.i.dpi); if (ida->img.i.npages > 1) len += sprintf(title+len," | page %d/%u", cpage+1, ida->img.i.npages); len += sprintf(title+len," | %d%%)", viewer_i2s(ida->zoom,100)); XtVaSetValues(app_shell, XtNtitle,title, /* XtNx,x, XtNy,y, */ XtNwidth,w, XtNheight,h, NULL); str = XmStringGenerate(title,NULL,XmMULTIBYTE_TEXT,NULL); XtVaSetValues(status,XmNlabelString,str,NULL); XmStringFree(str); free(title); } static int load_file(int nr, int np) { if(nr < 0 || nr >= nfiles) return -1; npages = viewer_loadimage(ida,files[nr],np); if (-1 == npages) return -1; resize_shell(); #if 0 XmListSelectPos(wlist,nr+1,False); cfile = nr; #endif return npages; } char* load_tmpfile(char *base) { char *tmpdir; char *filename; tmpdir = getenv("TMPDIR"); if (NULL == tmpdir) tmpdir="/tmp"; filename = malloc(strlen(tmpdir)+strlen(base)+16); sprintf(filename,"%s/%s-XXXXXX",tmpdir,base); return filename; } static void load_logo(void) { static unsigned char logo[] = { #include "logo.h" }; char *filename = load_tmpfile("ida-logo"); int fd; fd = mkstemp(filename); write(fd,logo,sizeof(logo)); close(fd); cpage = 0; npages = 1; if (0 < viewer_loadimage(ida,filename,cpage)) { ida->file = "ida " VERSION; resize_shell(); } unlink(filename); free(filename); } static void load_stdin(void) { char *filename = load_tmpfile("ida-stdin"); char buf[4096]; int rc,fd; fd = mkstemp(filename); for (;;) { rc = read(0,buf,sizeof(buf)); if (rc <= 0) break; write(fd,buf,rc); } close(fd); cpage = 0; npages = 1; if (0 < viewer_loadimage(ida,filename,cpage)) { ida->file = "stdin"; resize_shell(); } unlink(filename); free(filename); } void next_ac(Widget widget, XEvent *event, String *params, Cardinal *num) { for (;;) { if (cfile >= nfiles-1) return; cfile++; cpage = 0; if (0 <= load_file(cfile,cpage)) break; } } void prev_ac(Widget widget, XEvent *event, String *params, Cardinal *num) { for (;;) { if (cfile < 1) return; cfile--; cpage = 0; if (0 <= load_file(cfile,cpage)) break; } } void next_page_ac(Widget widget, XEvent *event, String *params, Cardinal *num) { for (;;) { if (cpage >= npages-1) return; cpage++; if (0 <= load_file(cfile,cpage)) break; } } void prev_page_ac(Widget widget, XEvent *event, String *params, Cardinal *num) { for (;;) { if (cpage <= 0) return; cpage--; if (0 <= load_file(cfile,cpage)) break; } } void zoom_ac(Widget widget, XEvent *event, String *params, Cardinal *num) { int zoom; if (0 == *num) return; if (0 == strcasecmp(params[0],"auto")) { viewer_autozoom(ida); return; } if (0 == strcasecmp(params[0],"inc")) { zoom = ida->zoom+1; } else if (0 == strcasecmp(params[0],"dec")) { zoom = ida->zoom-1; } else { zoom = atoi(params[0]); } viewer_setzoom(ida,zoom); resize_shell(); } void scroll_ac(Widget widget, XEvent *event, String *params, Cardinal *num) { fprintf(stderr,"Scroll(): %s\n",XtName(widget)); } /* ---------------------------------------------------------------------- */ void new_file(char *name, int complain) { struct stat st; int n; if (curl_is_url(name)) goto load; if (0 == strncasecmp(name,"file:",5)) name += 5; if (-1 == stat(name,&st)) { if (complain) fprintf(stderr,"stat %s: %s\n",name,strerror(errno)); return; } switch (st.st_mode & S_IFMT) { case S_IFDIR: browser_window(name); break; case S_IFREG: goto load; break; } return; load: n = list_append(name); list_update(); cpage = 0; load_file(n,cpage); } static void load_done_cb(Widget widget, XtPointer clientdata, XtPointer call_data) { XmFileSelectionBoxCallbackStruct *cb = call_data; char *line; if (cb->reason == XmCR_OK) { line = XmStringUnparse(cb->value,NULL, XmMULTIBYTE_TEXT,XmMULTIBYTE_TEXT, NULL,0,0); new_file(line,1); } XtUnmanageChild(widget); } void load_ac(Widget widget, XEvent *event, String *params, Cardinal *num) { Widget help; if (NULL == loadbox) { loadbox = XmCreateFileSelectionDialog(app_shell,"load",NULL,0); help = XmFileSelectionBoxGetChild(loadbox,XmDIALOG_HELP_BUTTON); XtUnmanageChild(help); XtAddCallback(loadbox,XmNokCallback,load_done_cb,NULL); XtAddCallback(loadbox,XmNcancelCallback,load_done_cb,NULL); } else { XmFileSelectionDoSearch(loadbox,NULL); } XtManageChild(loadbox); } void scan_ac(Widget widget, XEvent *event, String *params, Cardinal *num) { #ifdef HAVE_LIBSANE cpage = 0; if (*num) npages = viewer_loader_start(ida, &sane_loader, NULL, params[0], 0); else npages = viewer_loader_start(ida, &sane_loader, NULL, "", 0); if (-1 == npages) return; ida->file = "scanned image"; resize_shell(); #endif } /* ---------------------------------------------------------------------- */ void do_save_print(void) { FILE *fp; if (save_filename) { XtUnmanageChild(savebox); ptr_busy(); if (NULL == (fp = fopen(save_filename,"wb"))) { fprintf(stderr,"save: can't open %s: %s\n", save_filename,strerror(errno)); } else if (-1 == cwriter->write(fp,&ida->img)) { fclose(fp); fprintf(stderr,"saving %s FAILED",save_filename); } else { fclose(fp); list_append(save_filename); list_update(); } ptr_idle(); } if (print_command) { XtUnmanageChild(printbox); ptr_busy(); if (NULL == (fp = popen(print_command,"w"))) { fprintf(stderr,"print: can't exec %s: %s\n", print_command,strerror(errno)); } else { if (-1 == cwriter->write(fp,&ida->img)) fprintf(stderr,"printing FAILED"); fclose(fp); } ptr_idle(); } } static void save_done_cb(Widget widget, XtPointer clientdata, XtPointer call_data) { XmFileSelectionBoxCallbackStruct *cb = call_data; if (cb->reason == XmCR_OK) { print_command = NULL; save_filename = XmStringUnparse(cb->value,NULL, XmMULTIBYTE_TEXT,XmMULTIBYTE_TEXT, NULL,0,0); if (cwriter->conf) { cwriter->conf(widget,&ida->img); } else { do_save_print(); } } else { XtUnmanageChild(widget); } } static void save_fmt_cb(Widget widget, XtPointer clientdata, XtPointer call_data) { cwriter = clientdata; } static void save_ext_cb(Widget widget, XtPointer clientdata, XtPointer call_data) { Widget option = clientdata; Widget menu; WidgetList children; Cardinal nchildren; struct ida_writer *wr = NULL; struct list_head *item; char *name,*ext; int i,j,pick; name = XmTextGetString(widget); ext = strrchr(name,'.'); if (NULL == ext) return; if (strchr(ext,'/')) return; ext++; i = 0; pick = -1; list_for_each(item,&writers) { wr = list_entry(item, struct ida_writer, list); for (j = 0; NULL != wr->ext[j]; j++) if (0 == strcasecmp(ext,wr->ext[j])) pick = i; if (-1 != pick) break; i++; } if (-1 == pick) return; XtVaGetValues(option,XmNsubMenuId,&menu,NULL); XtVaGetValues(menu,XtNchildren,&children, XtNnumChildren,&nchildren,NULL); XtVaSetValues(option,XmNmenuHistory,children[pick],NULL); cwriter = wr; } static void save_ac(Widget widget, XEvent *event, String *params, Cardinal *num) { Widget help,menu,option,push,text; Arg args[2]; struct ida_writer *wr = NULL; struct list_head *item; if (NULL == savebox) { savebox = XmCreateFileSelectionDialog(app_shell,"save",NULL,0); help = XmFileSelectionBoxGetChild(savebox,XmDIALOG_HELP_BUTTON); text = XmFileSelectionBoxGetChild(savebox,XmDIALOG_TEXT); XtUnmanageChild(help); menu = XmCreatePulldownMenu(savebox,"formatM",NULL,0); XtSetArg(args[0],XmNsubMenuId,menu); option = XmCreateOptionMenu(savebox,"format",args,1); XtManageChild(option); list_for_each(item,&writers) { wr = list_entry(item, struct ida_writer, list); push = XtVaCreateManagedWidget(wr->label, xmPushButtonWidgetClass,menu, NULL); XtAddCallback(push,XmNactivateCallback,save_fmt_cb,wr); } cwriter = list_entry(writers.next, struct ida_writer, list); XtAddCallback(text,XmNvalueChangedCallback,save_ext_cb,option); XtAddCallback(savebox,XmNokCallback,save_done_cb,NULL); XtAddCallback(savebox,XmNcancelCallback,save_done_cb,NULL); } else { XmFileSelectionDoSearch(savebox,NULL); } XtManageChild(savebox); } /* ---------------------------------------------------------------------- */ static void print_done_cb(Widget widget, XtPointer clientdata, XtPointer call_data) { XmSelectionBoxCallbackStruct *cb = call_data; if (cb->reason == XmCR_OK) { save_filename = NULL; print_command = XmStringUnparse(cb->value,NULL, XmMULTIBYTE_TEXT,XmMULTIBYTE_TEXT, NULL,0,0); cwriter = &ps_writer; cwriter->conf(widget,&ida->img); } else { XtUnmanageChild(widget); } } static void print_ac(Widget widget, XEvent *event, String *params, Cardinal *num) { if (NULL == printbox) { printbox = XmCreatePromptDialog(app_shell,"print",NULL,0); XtUnmanageChild(XmSelectionBoxGetChild(printbox,XmDIALOG_HELP_BUTTON)); XtAddCallback(printbox,XmNokCallback,print_done_cb,NULL); XtAddCallback(printbox,XmNcancelCallback,print_done_cb,NULL); } XtManageChild(printbox); } /* ---------------------------------------------------------------------- */ static struct ida_op *ops[] = { &desc_flip_vert, &desc_flip_horz, &desc_rotate_cw, &desc_rotate_ccw, &desc_invert, &desc_crop, &desc_autocrop, &desc_grayscale, NULL }; void filter_ac(Widget widget, XEvent *event, String *params, Cardinal *num) { struct ida_op *op = NULL; int i; if (*num < 1) return; for (i = 0; NULL != ops[i]; i++) { op = ops[i]; if (0 == strcasecmp(op->name,params[0])) break; } if (NULL == ops[i]) { fprintf(stderr,"Oops: unknown filter: %s\n",params[0]); return; } viewer_start_op(ida,op,NULL); if (ida->op_src.i.width != ida->img.i.width || ida->op_src.i.height != ida->img.i.height) resize_shell(); } void f3x3_ac(Widget widget, XEvent *event, String *params, Cardinal *num) { struct op_3x3_parm p; if (*num < 9) { fprintf(stderr,"F3x3: wrong number of args (%d, need 9)\n",*num); return; } memset(&p,0,sizeof(p)); p.f1[0] = atoi(params[0]); p.f1[1] = atoi(params[1]); p.f1[2] = atoi(params[2]); p.f2[0] = atoi(params[3]); p.f2[1] = atoi(params[4]); p.f2[2] = atoi(params[5]); p.f3[0] = atoi(params[6]); p.f3[1] = atoi(params[7]); p.f3[2] = atoi(params[8]); if (*num > 9) p.mul = atoi(params[ 9]); if (*num > 10) p.div = atoi(params[10]); if (*num > 11) p.add = atoi(params[11]); if (debug) { fprintf(stderr,"f3x3: -----------\n"); fprintf(stderr,"f3x3: %3d %3d %3d\n",p.f1[0],p.f1[1],p.f1[2]); fprintf(stderr,"f3x3: %3d %3d %3d\n",p.f2[0],p.f2[1],p.f2[2]); fprintf(stderr,"f3x3: %3d %3d %3d\n",p.f3[0],p.f3[1],p.f3[2]); fprintf(stderr,"f3x3: *%d/%d+%d\n",p.mul,p.div,p.add); } viewer_start_op(ida,&desc_3x3,&p); } void undo_ac(Widget widget, XEvent *event, String *params, Cardinal *num) { Widget msgbox; int resize; resize = (ida->undo.i.width != ida->img.i.width || ida->undo.i.height != ida->img.i.height); if (-1 == viewer_undo(ida)) { msgbox = XmCreateInformationDialog(app_shell,"noundobox",NULL,0); XtUnmanageChild(XmMessageBoxGetChild(msgbox,XmDIALOG_HELP_BUTTON)); XtUnmanageChild(XmMessageBoxGetChild(msgbox,XmDIALOG_CANCEL_BUTTON)); XtAddCallback(msgbox,XmNokCallback,destroy_cb,msgbox); XtManageChild(msgbox); } else { if (resize) resize_shell(); } } /* ---------------------------------------------------------------------- */ struct ida_prompt { Widget shell; Widget box; Widget scale; Widget text; int apply; int value; int decimal; int factor; /* 10^decimal */ void (*notify)(int value, int preview); }; static void prompt_setvalue(struct ida_prompt *me, int value, int scale, int text) { char str[32]; int min,max; if (me->value == value) return; XtVaGetValues(me->scale,XmNminimum,&min,XmNmaximum,&max,NULL); if (value < min || value > max) return; me->value = value; if (scale) XmScaleSetValue(me->scale,value); if (text) { if (me->decimal) { sprintf(str,"%*.*f",me->decimal+2,me->decimal, (float)value/me->factor); } else { sprintf(str,"%d",value); } XmTextSetString(me->text,str); } if (me->notify) me->notify(value,1); } static void prompt_scale_cb(Widget widget, XtPointer client_data, XtPointer calldata) { struct ida_prompt *me = client_data; XmScaleCallbackStruct *cd = calldata; prompt_setvalue(me,cd->value,0,1); } static void prompt_text_cb(Widget widget, XtPointer client_data, XtPointer calldata) { struct ida_prompt *me = client_data; float fvalue; int value; if (me->decimal) { fvalue = atof(XmTextGetString(me->text)); fvalue += 0.5/me->factor; value = (int)(fvalue * me->factor); } else { value = atoi(XmTextGetString(me->text)); } prompt_setvalue(me,value,1,0); } static void prompt_box_cb(Widget widget, XtPointer client_data, XtPointer calldata) { struct ida_prompt *me = client_data; XmSelectionBoxCallbackStruct *cd = calldata; if (XmCR_OK == cd->reason) me->apply = 1; XtDestroyWidget(me->shell); } static void prompt_shell_cb(Widget widget, XtPointer client_data, XtPointer calldata) { struct ida_prompt *me = client_data; if (me->apply) me->notify(me->value,0); else viewer_cancel_preview(ida); free(me); } static void prompt_init(char *name, int decimal, int value, void (*notify)(int value, int preview)) { struct ida_prompt *me; me = malloc(sizeof(*me)); memset(me,0,sizeof(*me)); if (decimal) { int i; me->decimal = decimal; me->factor = 1; for (i = 0; i < decimal; i++) me->factor *= 10; } me->notify = notify; me->box = XmCreatePromptDialog(app_shell,name,NULL,0); me->shell = XtParent(me->box); me->text = XmSelectionBoxGetChild(me->box,XmDIALOG_TEXT); XmdRegisterEditres(XtParent(me->box)); XtUnmanageChild(XmSelectionBoxGetChild(me->box,XmDIALOG_HELP_BUTTON)); me->scale = XtVaCreateManagedWidget("scale",xmScaleWidgetClass, me->box,NULL); XtAddCallback(me->scale,XmNdragCallback,prompt_scale_cb,me); XtAddCallback(me->scale,XmNvalueChangedCallback,prompt_scale_cb,me); XtAddCallback(me->text,XmNvalueChangedCallback,prompt_text_cb,me); XtAddCallback(me->box,XmNokCallback,prompt_box_cb,me); XtAddCallback(me->box,XmNcancelCallback,prompt_box_cb,me); XtAddCallback(me->shell,XmNdestroyCallback,prompt_shell_cb,me); XtManageChild(me->box); prompt_setvalue(me,value,1,1); } /* ---------------------------------------------------------------------- */ static void gamma_notify(int value, int preview) { struct op_map_parm param; float gamma = (float)value/100; param.red = op_map_nothing; param.red.gamma = gamma; param.green = param.red; param.blue = param.red; if (preview) { viewer_start_preview(ida,&desc_map,¶m); } else { gamma_val = value; viewer_start_op(ida,&desc_map,¶m); } } void gamma_ac(Widget widget, XEvent *event, String *params, Cardinal *num) { prompt_init("gamma",2,gamma_val,gamma_notify); } static void bright_notify(int value, int preview) { struct op_map_parm param; param.red = op_map_nothing; param.red.bottom += value; param.red.top += value; param.green = param.red; param.blue = param.red; if (preview) { viewer_start_preview(ida,&desc_map,¶m); } else { bright_val = value; viewer_start_op(ida,&desc_map,¶m); } } void bright_ac(Widget widget, XEvent *event, String *params, Cardinal *num) { prompt_init("bright",0,bright_val,bright_notify); } static void contrast_notify(int value, int preview) { struct op_map_parm param; param.red = op_map_nothing; param.red.bottom -= value; param.red.top += value; param.green = param.red; param.blue = param.red; if (preview) { viewer_start_preview(ida,&desc_map,¶m); } else { contrast_val = value; viewer_start_op(ida,&desc_map,¶m); } } void contrast_ac(Widget widget, XEvent *event, String *params, Cardinal *num) { prompt_init("contrast",0,contrast_val,contrast_notify); } static void rotate_notify(int value, int preview) { struct op_rotate_parm parm; parm.angle = value; if (preview) { viewer_start_preview(ida,&desc_rotate,&parm); } else { rotate_val = value; viewer_start_op(ida,&desc_rotate,&parm); } } void rotate_ac(Widget widget, XEvent *event, String *params, Cardinal *num) { prompt_init("rotate",0,rotate_val,rotate_notify); } static void sharpe_notify(int value, int preview) { struct op_sharpe_parm parm; parm.factor = value; if (preview) { viewer_start_preview(ida,&desc_sharpe,&parm); } else { sharpe_val = value; viewer_start_op(ida,&desc_sharpe,&parm); } } void sharpe_ac(Widget widget, XEvent *event, String *params, Cardinal *num) { prompt_init("sharpe",0,sharpe_val,sharpe_notify); } void color_ac(Widget widget, XEvent *event, String *params, Cardinal *num) { color_init(&ida->img); } /* ---------------------------------------------------------------------- */ struct ida_resize { Widget dlg,tx,ty,tr,lock,size,res,label; int yupdate,xupdate,rupdate; int apply; }; static void resize_phys_size(struct ida_resize *h) { char buf[128]; XmString str; int dpi; float x,y; dpi = atoi(XmTextGetString(h->tr)); if (dpi) { x = (float)atoi(XmTextGetString(h->tx)) / dpi; y = (float)atoi(XmTextGetString(h->ty)) / dpi; sprintf(buf,"%.2f x %.2f inch\n%.2f x %.2f cm", x,y, x*2.54, y*2.54); } else { strcpy(buf,"unknown"); } str = XmStringGenerate(buf, NULL, XmMULTIBYTE_TEXT,NULL); XtVaSetValues(h->label,XmNlabelString,str,NULL); } static void resize_sync_cb(Widget widget, XtPointer client_data, XtPointer calldata) { struct ida_resize *h = client_data; char buf[32]; int i,lock,res; lock = XmToggleButtonGetState(h->lock); res = XmToggleButtonGetState(h->res); /* update text fields */ if (h->tx == widget) { if (h->xupdate) { h->xupdate--; return; } i = atoi(XmTextGetString(h->tx)); if (lock) { sprintf(buf,"%d",i * ida->img.i.height / ida->img.i.width); h->yupdate++; XmTextSetString(h->ty,buf); if (res) { sprintf(buf,"%d", ida->img.i.dpi * i / ida->img.i.width); h->rupdate++; XmTextSetString(h->tr,buf); } } else { if (res) { h->rupdate++; XmTextSetString(h->tr,"0"); } } resize_phys_size(h); } if (h->ty == widget) { if (h->yupdate) { h->yupdate--; return; } i = atoi(XmTextGetString(h->ty)); if (lock) { sprintf(buf,"%d",i * ida->img.i.width / ida->img.i.height); h->xupdate++; XmTextSetString(h->tx,buf); if (res) { sprintf(buf,"%d", ida->img.i.dpi * i / ida->img.i.height); h->rupdate++; XmTextSetString(h->tr,buf); } } else { if (res) { h->rupdate++; XmTextSetString(h->tr,"0"); } } resize_phys_size(h); } if (h->tr == widget) { if (h->rupdate) { h->rupdate--; return; } i = atoi(XmTextGetString(h->tr)); sprintf(buf,"%d", ida->img.i.width * i / ida->img.i.dpi); h->xupdate++; XmTextSetString(h->tx,buf); sprintf(buf,"%d", ida->img.i.height * i / ida->img.i.dpi); h->yupdate++; XmTextSetString(h->ty,buf); resize_phys_size(h); } /* radio buttons pressed */ if (h->size == widget && XmToggleButtonGetState(h->size)) { XmToggleButtonSetState(h->res,0,False); sprintf(buf,"%u", ida->img.i.dpi); h->rupdate++; XmTextSetString(h->tr,buf); XtVaSetValues(h->tr,XmNsensitive,False,NULL); resize_phys_size(h); } if (h->res == widget && XmToggleButtonGetState(h->res)) { XmToggleButtonSetState(h->size,0,False); XtVaSetValues(h->tr,XmNsensitive,True,NULL); } } static void resize_button_cb(Widget widget, XtPointer client_data, XtPointer calldata) { struct ida_resize *h = client_data; XmSelectionBoxCallbackStruct *cb = calldata; if (cb->reason == XmCR_OK) h->apply = 1; XtDestroyWidget(XtParent(h->dlg)); } static void resize_destroy(Widget widget, XtPointer client_data, XtPointer calldata) { struct ida_resize *h = client_data; struct op_resize_parm param; if (!h->apply) return; param.width = atoi(XmTextGetString(h->tx)); param.height = atoi(XmTextGetString(h->ty)); param.dpi = atoi(XmTextGetString(h->tr)); if (0 == param.width || 0 == param.height) { fprintf(stderr,"resize: invalid argument\n"); return; } viewer_start_op(ida,&desc_resize,¶m); resize_shell(); free(h); } static void resize_ac(Widget widget, XEvent *event, String *params, Cardinal *num) { Widget rc,rc2; char buf[32]; struct ida_resize *h; h = malloc(sizeof(*h)); memset(h,0,sizeof(*h)); h->dlg = XmCreatePromptDialog(app_shell,"resize",NULL,0); XmdRegisterEditres(XtParent(h->dlg)); XtUnmanageChild(XmSelectionBoxGetChild(h->dlg,XmDIALOG_SELECTION_LABEL)); XtUnmanageChild(XmSelectionBoxGetChild(h->dlg,XmDIALOG_HELP_BUTTON)); XtUnmanageChild(XmSelectionBoxGetChild(h->dlg,XmDIALOG_TEXT)); rc = XtVaCreateManagedWidget("rc", xmRowColumnWidgetClass,h->dlg, NULL); XtVaCreateManagedWidget("lx", xmLabelWidgetClass,rc, NULL); h->tx = XtVaCreateManagedWidget("tx", xmTextWidgetClass,rc, NULL); XtVaCreateManagedWidget("ly", xmLabelWidgetClass,rc, NULL); h->ty = XtVaCreateManagedWidget("ty", xmTextWidgetClass,rc, NULL); XtVaCreateManagedWidget("lr", xmLabelWidgetClass,rc, NULL); h->tr = XtVaCreateManagedWidget("tr", xmTextWidgetClass,rc, NULL); h->lock = XtVaCreateManagedWidget("lock", xmToggleButtonWidgetClass, rc, NULL); rc2 = XtVaCreateManagedWidget("rc", xmRowColumnWidgetClass,rc, NULL); h->size = XtVaCreateManagedWidget("size", xmToggleButtonWidgetClass, rc2, NULL); h->res = XtVaCreateManagedWidget("res", xmToggleButtonWidgetClass, rc2, NULL); XtVaCreateManagedWidget("phys", xmLabelWidgetClass,rc,NULL); h->label = XtVaCreateManagedWidget("label", xmLabelWidgetClass, rc, NULL); sprintf(buf,"%u",ida->img.i.width); XmTextSetString(h->tx,buf); sprintf(buf,"%u",ida->img.i.height); XmTextSetString(h->ty,buf); sprintf(buf,"%u",ida->img.i.dpi); XmTextSetString(h->tr,buf); XtVaSetValues(h->tr,XmNsensitive,False,NULL); XmToggleButtonSetState(h->lock,1,False); XmToggleButtonSetState(h->size,1,False); XmToggleButtonSetState(h->res,0,False); if (!ida->img.i.dpi) { XtVaSetValues(h->size,XmNsensitive,False,NULL); XtVaSetValues(h->res, XmNsensitive,False,NULL); } resize_phys_size(h); XtAddCallback(XtParent(h->dlg),XmNdestroyCallback,resize_destroy,h); XtAddCallback(h->dlg, XmNokCallback, resize_button_cb, h); XtAddCallback(h->dlg, XmNcancelCallback, resize_button_cb, h); XtAddCallback(h->tx, XmNvalueChangedCallback, resize_sync_cb, h); XtAddCallback(h->ty, XmNvalueChangedCallback, resize_sync_cb, h); XtAddCallback(h->tr, XmNvalueChangedCallback, resize_sync_cb, h); XtAddCallback(h->size,XmNvalueChangedCallback, resize_sync_cb, h); XtAddCallback(h->res, XmNvalueChangedCallback, resize_sync_cb, h); XtManageChild(h->dlg); } /* ---------------------------------------------------------------------- */ struct stderr_handler { Widget box; XmString str; int pipe,err; XtInputId id; }; static void stderr_input(XtPointer clientdata, int *src, XtInputId *id) { struct stderr_handler *h = clientdata; XmString item; Widget label; char buf[1024]; int rc; rc = read(h->pipe,buf,sizeof(buf)-1); if (rc <= 0) { /* Oops */ XtRemoveInput(h->id); close(h->pipe); XtDestroyWidget(h->box); free(h); } buf[rc] = 0; write(h->err,buf,rc); item = XmStringGenerate(buf, NULL, XmMULTIBYTE_TEXT,NULL); h->str = XmStringConcatAndFree(h->str,item); label = XmMessageBoxGetChild(h->box,XmDIALOG_MESSAGE_LABEL); XtVaSetValues(label,XmNlabelString,h->str,NULL); XtManageChild(h->box); } static void stderr_ok_cb(Widget widget, XtPointer clientdata, XtPointer call_data) { struct stderr_handler *h = clientdata; XmStringFree(h->str); h->str = XmStringGenerate("", NULL, XmMULTIBYTE_TEXT,NULL); XtUnmanageChild(h->box); } static void stderr_close_cb(Widget widget, XtPointer clientdata, XtPointer call_data) { struct stderr_handler *h = clientdata; XmStringFree(h->str); h->str = XmStringGenerate("", NULL, XmMULTIBYTE_TEXT,NULL); } static void stderr_init(void) { struct stderr_handler *h; int p[2]; h = malloc(sizeof(*h)); memset(h,0,sizeof(*h)); h->str = XmStringGenerate("", NULL, XmMULTIBYTE_TEXT,NULL); h->box = XmCreateErrorDialog(app_shell,"errbox",NULL,0); XtUnmanageChild(XmMessageBoxGetChild(h->box,XmDIALOG_HELP_BUTTON)); XtUnmanageChild(XmMessageBoxGetChild(h->box,XmDIALOG_CANCEL_BUTTON)); XtAddCallback(h->box,XmNokCallback,stderr_ok_cb,h); XtAddCallback(XtParent(h->box),XmNpopdownCallback,stderr_close_cb,h); XSync(XtDisplay(app_shell),False); if (!debug) { pipe(p); h->err = dup(2); dup2(p[1],2); close(p[1]); h->pipe = p[0]; h->id = XtAppAddInput(app_context,h->pipe,(XtPointer)XtInputReadMask, stderr_input,h); } } /* ---------------------------------------------------------------------- */ static void create_mainwindow(void) { Widget img; XmdRegisterEditres(app_shell); view = XmCreateScrolledWindow(app_shell,"view",NULL,0); XtManageChild(view); img = XtVaCreateManagedWidget("image", xmDrawingAreaWidgetClass,view,NULL); XtAddCallback(img,XmNdestinationCallback,selection_dest,NULL); XtAddCallback(img,XmNconvertCallback,selection_convert,NULL); dnd_add(img); ida = viewer_init(img); XtInstallAllAccelerators(img,app_shell); } static void usage(void) { fprintf(stderr, "ida " VERSION " - image viewer & editor\n" "usage: ida [ options ] [ files ]\n" "options:\n" " -h, -help this text\n" " -pcd n pick PhotoCD size (n = 1 .. 5, default 3)\n" " -d, -debug enable debug messages\n"); exit(0); } int main(int argc, char *argv[]) { int i, files, zero = 0; struct stat st; Pixel background; #if 0 setlocale(LC_ALL,""); if (0 == strcasecmp("utf-8", nl_langinfo(CODESET))) { /* ### FIXME ### * for not-yet known reasons ida crashes somewhere deep in * the Motif libraries when running in utf-8 locale ... */ setenv("LC_ALL", "POSIX", 1); setlocale(LC_ALL,""); } #endif binary = argv[0]; ida_init_config(); ida_read_config(); XtSetLanguageProc(NULL,NULL,NULL); app_shell = XtAppInitialize(&app_context, "Ida", opt_desc, opt_count, &argc, argv, fallback_ressources, NULL, 0); dpy = XtDisplay(app_shell); XtGetApplicationResources(app_shell,&args, args_desc,args_count, NULL,0); pcd_res = GET_PHOTOCD_RES(); sane_res = GET_SANE_RES(); if (args.help) usage(); if (args.debug) { debug=1; xdnd_debug = 1; XSynchronize(dpy,1); } XtAppAddActions(app_context, actionTable, sizeof(actionTable) / sizeof(XtActionsRec)); if (0) { XtAddCallback(XmGetXmDisplay(dpy),XmNnoFontCallback, display_cb,NULL); XtAddCallback(XmGetXmDisplay(dpy),XmNnoRenditionCallback, display_cb,NULL); } XtVaGetValues(app_shell, XtNbackground,&background, NULL); x11_color_init(app_shell,&gray); x11_icons_init(dpy, background /* x11_gray */); stderr_init(); ipc_init(); wm_delete_window = XInternAtom(dpy,"WM_DELETE_WINDOW",False); create_mainwindow(); create_control(); XtRealizeWidget(app_shell); ptr_register(ida->widget); ptr_register(control_shell); /* handle cmd line args */ if (2 == argc && 0 == strcmp(argv[1],"-")) { load_stdin(); } else if (argc > 1) { for (files = 0, i = 1; i < argc; i++) { if (curl_is_url(argv[i])) { list_append(argv[i]); files++; continue; } if (-1 == stat(argv[i],&st)) { if (debug) fprintf(stderr,"stat %s: %s\n",argv[i],strerror(errno)); continue; } switch (st.st_mode & S_IFMT) { case S_IFDIR: browser_window(argv[i]); break; case S_IFREG: list_append(argv[i]); files++; break; } } if (files) { list_update(); next_ac(ida->widget,NULL,NULL,&zero); } } if (NULL == ida->file) load_logo(); XtAppMainLoop(app_context); return 0; /* keep compiler happy */ } fbi-2.10/filelist.c0000644000175000017500000004020212506525033012302 0ustar jmmjmm/* * file list management ("virtual photo album"). * (c) 2003 Gerd Hoffmann * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "RegEdit.h" #include "ida.h" #include "readers.h" #include "viewer.h" #include "browser.h" #include "filter.h" #include "x11.h" #include "selections.h" #include "filebutton.h" #include "filelist.h" #include "xdnd.h" #include "idaconfig.h" /*----------------------------------------------------------------------*/ struct list_handle; struct list_handle { char *filename; struct list_head files; Widget shell; Widget scroll; Widget container; Widget status; XmString details[DETAIL_COUNT+1]; Widget loadbox; Widget savebox; XtWorkProcId wproc; }; /* ---------------------------------------------------------------------- */ static void filelist_add(struct list_handle *h, char *filename) { struct file_button *file; char *tmp; /* fixup filename */ if (0 == strncmp(filename,"file:",5)) filename += 5; if (NULL != (tmp = strchr(filename,'\n'))) *tmp = 0; if (NULL != (tmp = strchr(filename,'\r'))) *tmp = 0; if (0 == strlen(filename)) return; /* add file */ file = malloc(sizeof(*file)); memset(file,0,sizeof(*file)); tmp = strrchr(filename,'/'); if (!tmp) goto oops; file->basename = strdup(tmp+1); file->filename = strdup(filename); if (-1 == stat(file->filename,&file->st)) { fprintf(stderr,"stat %s: %s\n",file->filename,strerror(errno)); goto oops; } if (!S_ISREG(file->st.st_mode)) { fprintf(stderr,"%s: not a regular file\n",file->filename); goto oops; } list_add_tail(&file->window,&h->files); file_createwidgets(h->container, file); XtManageChild(file->widget); fileinfo_queue(file); container_relayout(h->container); return; oops: if (file->filename) free(file->filename); if (file->basename) free(file->basename); free(file); } static void filelist_file(struct list_handle *h, char *filename) { if (h->filename == filename) return; if (h->filename) free(h->filename); h->filename = strdup(filename); XtVaSetValues(h->shell,XtNtitle,h->filename,NULL); } static void filelist_read(struct list_handle *h, char *filename) { FILE *fp; char line[128]; fp = fopen(filename,"r"); if (NULL == fp) { fprintf(stderr,"open %s: %s\n",filename,strerror(errno)); return; } while (NULL != fgets(line, sizeof(line), fp)) { filelist_add(h, line); } fclose(fp); filelist_file(h,filename); container_relayout(h->container); } static void filelist_write(struct list_handle *h, char *filename) { struct file_button *file; struct list_head *item; FILE *fp; fp = fopen(filename,"w"); if (NULL == fp) { fprintf(stderr,"open %s: %s\n",filename,strerror(errno)); return; } list_for_each(item, &h->files) { file = list_entry(item, struct file_button, window); fprintf(fp,"%s\n",file->filename); } fclose(fp); filelist_file(h,filename); } static void filelist_delall(struct list_handle *h) { struct file_button *file; struct list_head *item; list_for_each(item, &h->files) { file = list_entry(item, struct file_button, window); XtUnmanageChild(file->widget); XtDestroyWidget(file->widget); } } /* ---------------------------------------------------------------------- */ /* receive data (drops, paste) */ static Atom targets[16]; static Cardinal ntargets; static void filelist_xfer(Widget widget, XtPointer clientdata, XtPointer call_data) { struct list_handle *h = clientdata; XmSelectionCallbackStruct *scs = call_data; unsigned char *cdata = scs->value; unsigned long *ldata = scs->value; Atom target = 0; unsigned int i,j,pending; char *file; if (debug) { char *y = !scs->type ? NULL : XGetAtomName(dpy,scs->type); char *t = !scs->target ? NULL : XGetAtomName(dpy,scs->target); char *s = !scs->selection ? NULL : XGetAtomName(dpy,scs->selection); fprintf(stderr,"list: id=%p target=%s type=%s selection=%s\n", scs->transfer_id,t,y,s); if (y) XFree(y); if (t) XFree(t); if (s) XFree(s); } pending = scs->remaining; if (scs->target == XA_TARGETS) { /* look if we find a target we can deal with ... */ for (i = 0; !target && i < scs->length; i++) { for (j = 0; j < ntargets; j++) { if (ldata[i] == targets[j]) { target = ldata[i]; break; } } } if (target) { XmTransferValue(scs->transfer_id, target, filelist_xfer, clientdata, XtLastTimestampProcessed(dpy)); pending++; } if (debug) { fprintf(stderr,"list: available targets: "); for (i = 0; i < scs->length; i++) { char *name = !ldata[i] ? NULL : XGetAtomName(dpy,ldata[i]); fprintf(stderr,"%s%s", i != 0 ? ", " : "", name); XFree(name); } fprintf(stderr,"\n"); if (0 == scs->length) fprintf(stderr,"list: Huh? no TARGETS available?\n"); } } if (scs->target == XA_FILE_NAME || scs->target == XA_FILE) { /* load file */ if (debug) fprintf(stderr,"list: => \"%s\"\n",cdata); filelist_add(h,cdata); } if (scs->target == _NETSCAPE_URL) { /* load file */ if (debug) fprintf(stderr,"list: => \"%s\"\n",cdata); filelist_add(h,cdata); } if (scs->target == MIME_TEXT_URI_LIST) { /* load file(s) */ for (file = strtok(cdata,"\r\n"); NULL != file; file = strtok(NULL,"\r\n")) { if (debug) fprintf(stderr,"list: => \"%s\"\n",file); filelist_add(h,file); } } XFree(scs->value); if (1 == pending) { /* all done -- clean up */ if (debug) fprintf(stderr,"list: all done\n"); XmTransferDone(scs->transfer_id, XmTRANSFER_DONE_SUCCEED); XdndDropFinished(widget,scs); } } static void filelist_dest_cb(Widget w, XtPointer clientdata, XtPointer call_data) { XmDestinationCallbackStruct *dcs = call_data; if (debug) fprintf(stderr,"list: xfer id=%p\n",dcs->transfer_id); XmTransferValue(dcs->transfer_id, XA_TARGETS, filelist_xfer, clientdata, XtLastTimestampProcessed(dpy)); } /*----------------------------------------------------------------------*/ static void filelist_new_cb(Widget widget, XtPointer clientdata, XtPointer call_data) { struct list_handle *h = clientdata; filelist_delall(h); if (h->filename) { free(h->filename); h->filename = NULL; } XtVaSetValues(h->shell,XtNtitle,"new list",NULL); } static void init_file_box(Widget box, char *filename) { char *dir,*file; XmString s1; if (NULL == filename) { dir = strdup(ida_lists); } else { dir = strdup(filename); file = strrchr(dir,'/'); if (NULL == file) return; *file = 0; file++; } s1 = XmStringGenerate(dir, NULL, XmMULTIBYTE_TEXT, NULL); XtVaSetValues(box, XmNdirectory, s1, XmNpattern, NULL, NULL); XmFileSelectionDoSearch(box,NULL); XmStringFree(s1); free(dir); } static void load_done_cb(Widget widget, XtPointer clientdata, XtPointer call_data) { XmFileSelectionBoxCallbackStruct *cb = call_data; struct list_handle *h = clientdata; char *filename; if (cb->reason == XmCR_OK) { filename = XmStringUnparse(cb->value,NULL, XmMULTIBYTE_TEXT,XmMULTIBYTE_TEXT, NULL,0,0); if (debug) fprintf(stderr,"read list from %s\n",filename); filelist_read(h, filename); } XtUnmanageChild(widget); } static void filelist_load_cb(Widget widget, XtPointer clientdata, XtPointer call_data) { struct list_handle *h = clientdata; Widget help; if (NULL == h->loadbox) { h->loadbox = XmCreateFileSelectionDialog(h->shell,"load",NULL,0); help = XmFileSelectionBoxGetChild(h->loadbox,XmDIALOG_HELP_BUTTON); XtUnmanageChild(help); XtAddCallback(h->loadbox,XmNokCallback,load_done_cb,h); XtAddCallback(h->loadbox,XmNcancelCallback,load_done_cb,h); } init_file_box(h->loadbox,h->filename); XtManageChild(h->loadbox); } static void save_done_cb(Widget widget, XtPointer clientdata, XtPointer call_data) { XmFileSelectionBoxCallbackStruct *cb = call_data; struct list_handle *h = clientdata; char *filename; if (cb->reason == XmCR_OK) { filename = XmStringUnparse(cb->value,NULL, XmMULTIBYTE_TEXT,XmMULTIBYTE_TEXT, NULL,0,0); if (debug) fprintf(stderr,"write list to %s\n",filename); filelist_write(h, filename); } XtUnmanageChild(widget); } static void filelist_save_as_cb(Widget widget, XtPointer clientdata, XtPointer call_data) { struct list_handle *h = clientdata; Widget help; if (NULL == h->savebox) { h->savebox = XmCreateFileSelectionDialog(h->shell,"save",NULL,0); help = XmFileSelectionBoxGetChild(h->savebox,XmDIALOG_HELP_BUTTON); XtUnmanageChild(help); XtAddCallback(h->savebox,XmNokCallback,save_done_cb,h); XtAddCallback(h->savebox,XmNcancelCallback,save_done_cb,h); } init_file_box(h->savebox,h->filename); XtManageChild(h->savebox); } static void filelist_save_cb(Widget widget, XtPointer clientdata, XtPointer call_data) { struct list_handle *h = clientdata; if (h->filename) { filelist_write(h, h->filename); } else { filelist_save_as_cb(widget, h, call_data); } } static void filelist_destroy(Widget widget, XtPointer clientdata, XtPointer call_data) { struct list_handle *h = clientdata; if (h->filename) free(h->filename); ptr_unregister(h->shell); free(h); } static void filelist_list_load(Widget widget, XtPointer clientdata, XtPointer call_data) { struct list_handle *h = clientdata; filelist_delall(h); filelist_read(h, XtName(widget)); } static void filelist_builddir(Widget menu, char *path, XtPointer clientdata) { Widget push,submenu; XmString str; char filename[1024]; struct dirent *ent; struct stat st; DIR *dir; dir = opendir(path); while (NULL != (ent = readdir(dir))) { if (ent->d_name[0] == '.') continue; snprintf(filename,sizeof(filename),"%s/%s", path,ent->d_name); if (-1 == lstat(filename,&st)) continue; str = XmStringGenerate(ent->d_name,NULL, XmMULTIBYTE_TEXT,NULL); if (S_ISREG(st.st_mode)) { push = XtVaCreateManagedWidget(filename, xmPushButtonWidgetClass,menu, XmNlabelString,str, NULL); XtAddCallback(push,XmNactivateCallback,filelist_list_load,clientdata); } if (S_ISDIR(st.st_mode)) { submenu = XmCreatePulldownMenu(menu,"subdirM",NULL,0); XtVaCreateManagedWidget("subdir",xmCascadeButtonWidgetClass,menu, XmNlabelString,str, XmNsubMenuId,submenu, NULL); filelist_builddir(submenu,filename,clientdata); } XmStringFree(str); } closedir(dir); } static void filelist_lists(Widget widget, XtPointer clientdata, XtPointer call_data) { WidgetList children,list; Cardinal nchildren; int i; XtVaGetValues(widget, XtNchildren,&children, XtNnumChildren,&nchildren, NULL); list = malloc(sizeof(Widget*)*nchildren); memcpy(list,children,sizeof(Widget*)*nchildren); for (i = 0; i < nchildren; i++) XtDestroyWidget(list[i]); free(list); filelist_builddir(widget,ida_lists,clientdata); } static void filelist_action_cb(Widget widget, XtPointer clientdata, XtPointer call_data) { XmContainerSelectCallbackStruct *cd = call_data; char *file; if (XmCR_DEFAULT_ACTION == cd->reason && 1 == cd->selected_item_count) { file = XtName(cd->selected_items[0]); if (debug) fprintf(stderr,"browser: action %s\n", file); new_file(file,1); } } /*----------------------------------------------------------------------*/ void filelist_window(void) { Widget form,clip,menubar,menu,push; struct list_handle *h; Arg args[8]; int n = 0; if (0 == ntargets) { /* first time init */ targets[ntargets++] = MIME_TEXT_URI_LIST; targets[ntargets++] = XA_FILE_NAME; targets[ntargets++] = XA_FILE; targets[ntargets++] = _NETSCAPE_URL; } h = malloc(sizeof(*h)); if (NULL == h) { fprintf(stderr,"out of memory"); return; } memset(h,0,sizeof(*h)); INIT_LIST_HEAD(&h->files); h->shell = XtVaAppCreateShell("filelist","Ida", topLevelShellWidgetClass, dpy, XtNclientLeader,app_shell, XmNdeleteResponse,XmDESTROY, XtNtitle,"new list", NULL); XmdRegisterEditres(h->shell); XtAddCallback(h->shell,XtNdestroyCallback,filelist_destroy,h); /* widgets */ form = XtVaCreateManagedWidget("form", xmFormWidgetClass, h->shell, NULL); menubar = XmCreateMenuBar(form,"cbar",NULL,0); XtManageChild(menubar); h->status = XtVaCreateManagedWidget("status",xmLabelWidgetClass, form, NULL); /* scrolled container */ h->details[0] = XmStringGenerate("Image", NULL, XmMULTIBYTE_TEXT,NULL); h->details[DETAIL_SIZE+1] = XmStringGenerate("Size", NULL, XmMULTIBYTE_TEXT,NULL); h->details[DETAIL_COMMENT+1] = XmStringGenerate("Comment", NULL, XmMULTIBYTE_TEXT,NULL); XtSetArg(args[n], XmNdetailColumnHeading, h->details); n++; XtSetArg(args[n], XmNdetailColumnHeadingCount, DETAIL_COUNT+1); n++; h->scroll = XmCreateScrolledWindow(form, "scroll", NULL, 0); XtManageChild(h->scroll); h->container = XmCreateContainer(h->scroll,"container", args,n); XtManageChild(h->container); XdndDropSink(h->container); XtAddCallback(h->scroll, XmNtraverseObscuredCallback, container_traverse_cb, NULL); XtAddCallback(h->container,XmNdefaultActionCallback, filelist_action_cb,h); XtAddCallback(h->container,XmNconvertCallback, container_convert_cb,h); XtAddCallback(h->container,XmNdestinationCallback, filelist_dest_cb,h); XtVaGetValues(h->scroll,XmNclipWindow,&clip,NULL); XtAddEventHandler(clip,StructureNotifyMask,True,container_resize_eh,NULL); /* menu - file */ menu = XmCreatePulldownMenu(menubar,"fileM",NULL,0); XtVaCreateManagedWidget("file",xmCascadeButtonWidgetClass,menubar, XmNsubMenuId,menu,NULL); push = XtVaCreateManagedWidget("new",xmPushButtonWidgetClass,menu,NULL); XtAddCallback(push,XmNactivateCallback,filelist_new_cb,h); push = XtVaCreateManagedWidget("load",xmPushButtonWidgetClass,menu,NULL); XtAddCallback(push,XmNactivateCallback,filelist_load_cb,h); push = XtVaCreateManagedWidget("save",xmPushButtonWidgetClass,menu,NULL); XtAddCallback(push,XmNactivateCallback,filelist_save_cb,h); push = XtVaCreateManagedWidget("saveas",xmPushButtonWidgetClass,menu,NULL); XtAddCallback(push,XmNactivateCallback,filelist_save_as_cb,h); XtVaCreateManagedWidget("sep",xmSeparatorWidgetClass,menu,NULL); push = XtVaCreateManagedWidget("close",xmPushButtonWidgetClass,menu,NULL); XtAddCallback(push,XmNactivateCallback,destroy_cb,h->shell); /* menu - edit */ menu = XmCreatePulldownMenu(menubar,"editM",NULL,0); XtVaCreateManagedWidget("edit",xmCascadeButtonWidgetClass,menubar, XmNsubMenuId,menu,NULL); container_menu_edit(menu,h->container, 0,1,1,1); /* menu - view */ menu = XmCreatePulldownMenu(menubar,"viewM",NULL,0); XtVaCreateManagedWidget("view",xmCascadeButtonWidgetClass,menubar, XmNsubMenuId,menu,NULL); container_menu_view(menu,h->container); /* menu - lists */ menu = XmCreatePulldownMenu(menubar,"listsM",NULL,0); XtVaCreateManagedWidget("lists",xmCascadeButtonWidgetClass,menubar, XmNsubMenuId,menu,NULL); XtAddCallback(menu, XmNmapCallback, filelist_lists, h); /* read dir and show window */ container_detail_cb(NULL,h->container,NULL); XtPopup(h->shell,XtGrabNone); ptr_register(h->shell); } void filelist_ac(Widget widget, XEvent *event, String *params, Cardinal *num_params) { filelist_window(); } fbi-2.10/filebutton.h0000644000175000017500000000424712506525033012660 0ustar jmmjmm#include #include #include "list.h" #define DETAIL_SIZE 0 #define DETAIL_COMMENT 1 #define DETAIL_COUNT 2 struct fileinfo_cache; struct file_button { /* file info */ char *filename; char *basename; unsigned char d_type; struct stat st; struct fileinfo *info; /* Widget + other X11 stuff */ Screen *screen; Widget widget; XmString label; XmString details[DETAIL_COUNT]; Pixmap small,large; /* lists */ struct list_head global; struct list_head window; /* private for file info + icon loader */ struct list_head queue; int state,y; struct ida_loader *loader; void *wdata; struct ida_image wimg; struct ida_image simg; }; void fileinfo_queue(struct file_button *file); void fileinfo_invalidate(char *filename); void file_set_icon(struct file_button *file, Pixmap s, Pixmap l); void file_set_info(struct file_button *file, struct fileinfo *info); /*----------------------------------------------------------------------*/ void container_detail_cb(Widget widget, XtPointer clientdata, XtPointer call_data); void container_spatial_cb(Widget widget, XtPointer clientdata, XtPointer call_data); void container_resize_eh(Widget widget, XtPointer clientdata, XEvent *event, Boolean *d); void container_convert_cb(Widget widget, XtPointer clientdata, XtPointer call_data); void container_traverse_cb(Widget scroll, XtPointer clientdata, XtPointer call_data); void container_menu_edit(Widget menu, Widget container, int cut, int copy, int paste, int del); void container_menu_view(Widget menu, Widget container); void container_menu_ops(Widget menu, Widget container); void container_relayout(Widget container); void container_setsize(Widget container); void container_delwidgets(Widget container); /*----------------------------------------------------------------------*/ int file_cmp_alpha(const struct file_button *aa, const struct file_button *bb); int file_createwidgets(Widget parent, struct file_button *file); fbi-2.10/lirc.h0000644000175000017500000000010712506525033011425 0ustar jmmjmmint lirc_fbi_init(void); int lirc_fbi_havedata(int* rc, char key[11]); fbi-2.10/curl.c0000644000175000017500000001673712506525033011454 0ustar jmmjmm#include #include #include #include #include #include #include #include #include #include #include "curl.h" /* curl globals */ static CURLM *curlm; static fd_set rd, wr, ex; /* my globals */ static int url_debug = 0; static int url_timeout = 30; /* my structs */ struct iobuf { off_t start; size_t size; char *data; }; struct url_state { char *path; CURL *curl; char errmsg[CURL_ERROR_SIZE]; off_t curl_pos; off_t buf_pos; struct iobuf buf; int eof; }; /* ---------------------------------------------------------------------- */ /* curl stuff */ static void __attribute__ ((constructor)) curl_init(void) { curl_global_init(CURL_GLOBAL_ALL); curlm = curl_multi_init(); } static void __attribute__ ((destructor)) curl_fini(void) { curl_multi_cleanup(curlm); curl_global_cleanup(); } static void curl_free_buffer(struct iobuf *buf) { if (buf->data) { free(buf->data); memset(buf,0,sizeof(*buf)); } } /* CURLOPT_WRITEFUNCTION */ static int curl_write(void *data, size_t size, size_t nmemb, void *handle) { struct url_state *h = handle; curl_free_buffer(&h->buf); h->buf.start = h->curl_pos; h->buf.size = size * nmemb; h->buf.data = malloc(h->buf.size); memcpy(h->buf.data, data, h->buf.size); if (url_debug) fprintf(stderr," put %5d @ %5d\n", (int)h->buf.size, (int)h->buf.start); h->curl_pos += h->buf.size; return h->buf.size; } /* do transfers */ static int curl_xfer(struct url_state *h) { CURLMcode rc; struct timeval tv; int count, maxfd; FD_ZERO(&rd); FD_ZERO(&wr); FD_ZERO(&ex); maxfd = -1; rc = curl_multi_fdset(curlm, &rd, &wr, &ex, &maxfd); if (CURLM_OK != rc) { fprintf(stderr,"curl_multi_fdset: %d %s\n",rc,h->errmsg); return -1; } if (-1 == maxfd) { /* wait 0.1 sec */ if (url_debug) fprintf(stderr,"wait 0.01 sec\n"); tv.tv_sec = 0; tv.tv_usec = 100000; } else { /* wait for data */ if (url_debug) fprintf(stderr,"select for data [maxfd=%d]\n",maxfd); tv.tv_sec = url_timeout; tv.tv_usec = 0; } switch (select(maxfd+1, &rd, &wr, &ex, &tv)) { case -1: /* Huh? */ perror("select"); exit(1); case 0: /* timeout */ return -1; } for (;;) { rc = curl_multi_perform(curlm,&count); if (CURLM_CALL_MULTI_PERFORM == rc) continue; if (CURLM_OK != rc) { fprintf(stderr,"curl_multi_perform: %d %s\n",rc,h->errmsg); return -1; } if (0 == count) h->eof = 1; break; } return 0; } /* curl setup */ static int curl_setup(struct url_state *h) { if (h->curl) { curl_multi_remove_handle(curlm,h->curl); curl_easy_cleanup(h->curl); } h->curl = curl_easy_init(); curl_easy_setopt(h->curl, CURLOPT_URL, h->path); curl_easy_setopt(h->curl, CURLOPT_ERRORBUFFER, h->errmsg); curl_easy_setopt(h->curl, CURLOPT_WRITEFUNCTION, curl_write); curl_easy_setopt(h->curl, CURLOPT_WRITEDATA, h); curl_multi_add_handle(curlm, h->curl); h->buf_pos = 0; h->curl_pos = 0; h->eof = 0; return 0; } /* ---------------------------------------------------------------------- */ /* GNU glibc custom stream interface */ static ssize_t url_read(void *handle, char *buf, size_t size) { struct url_state *h = handle; size_t bytes, total; off_t off; int count; if (url_debug) fprintf(stderr,"url_read(size=%d)\n",(int)size); for (total = 0; size > 0;) { if (h->buf.start <= h->buf_pos && h->buf.start + h->buf.size > h->buf_pos) { /* can satisfy from current buffer */ bytes = h->buf.start + h->buf.size - h->buf_pos; off = h->buf_pos - h->buf.start; if (bytes > size) bytes = size; memcpy(buf+total, h->buf.data + off, bytes); if (url_debug) fprintf(stderr," get %5d @ %5d [%5d]\n", (int)bytes, (int)h->buf_pos, (int)off); size -= bytes; total += bytes; h->buf_pos += bytes; continue; } if (h->buf_pos < h->buf.start) { /* seeking backwards -- restart transfer */ if (url_debug) fprintf(stderr," rewind\n"); curl_free_buffer(&h->buf); curl_setup(h); while (CURLM_CALL_MULTI_PERFORM == curl_multi_perform(curlm,&count)) /* nothing */; } if (h->eof) /* stop on eof */ break; /* fetch more data */ if (-1 == curl_xfer(h)) { if (0 == total) return -1; break; } } return total; } #if 0 static ssize_t url_write(void *handle, const char *buf, size_t size) { //struct url_state *h = handle; if (url_debug) fprintf(stderr,"url_write(size=%d)\n",(int)size); return -1; } #endif static int url_seek(void *handle, off64_t *pos, int whence) { struct url_state *h = handle; int rc = 0; if (url_debug) fprintf(stderr,"url_seek(pos=%d,whence=%d)\n", (int)(*pos), whence); switch (whence) { case SEEK_SET: h->buf_pos = *pos; break; case SEEK_CUR: h->buf_pos += *pos; break; case SEEK_END: rc = -1; } *pos = h->buf_pos; return rc; } static int url_close(void *handle) { struct url_state *h = handle; if (url_debug) fprintf(stderr,"url_close()\n"); curl_multi_remove_handle(curlm,h->curl); curl_easy_cleanup(h->curl); if (h->buf.data) free(h->buf.data); free(h->path); free(h); return 0; } static cookie_io_functions_t url_hooks = { .read = url_read, #if 0 .write = url_write, #endif .seek = url_seek, .close = url_close, }; static FILE *url_open(const char *path, const char *mode) { FILE *fp; struct url_state *h; int count; if (url_debug) fprintf(stderr,"url_open(%s,%s)\n",path,mode); h = malloc(sizeof(*h)); if (NULL == h) goto err; memset(h,0,sizeof(*h)); h->path = strdup(path); if (NULL == h->path) goto err; /* setup */ curl_setup(h); fp = fopencookie(h, mode, url_hooks); if (NULL == fp) goto err; /* connect + start fetching */ while (CURLM_CALL_MULTI_PERFORM == curl_multi_perform(curlm,&count)) /* nothing */; /* check for errors */ if (0 == count && NULL == h->buf.data) { errno = ENOENT; goto fetch_err; } /* all done */ return fp; fetch_err: curl_multi_remove_handle(curlm,h->curl); err: if (h->curl) curl_easy_cleanup(h->curl); if (h->path) free(h->path); if (h) free(h); return NULL; } /* ---------------------------------------------------------------------- */ /* hook into fopen using GNU ld's --wrap */ int curl_is_url(const char *url) { static char *protocols[] = { "ftp://", "http://", NULL, }; int i; for (i = 0; protocols[i] != NULL; i++) if (0 == strncasecmp(url, protocols[i], strlen(protocols[i]))) return 1; return 0; } FILE *__wrap_fopen(const char *path, const char *mode); FILE *__real_fopen(const char *path, const char *mode); FILE *__wrap_fopen(const char *path, const char *mode) { if (url_debug) fprintf(stderr,"fopen(%s,%s)\n",path,mode); /* catch URLs */ if (curl_is_url(path)) { if (strchr(mode,'w')) { fprintf(stderr,"write access over ftp/http is not supported, sorry\n"); return NULL; } return url_open(path,mode); } /* files passed to the real fopen */ return __real_fopen(path,mode); } fbi-2.10/RegEdit.h0000644000175000017500000000267412506525033012032 0ustar jmmjmm/* $XConsortium: RegEdit.h /main/5 1995/07/15 20:44:09 drk $ */ /* * Motif * * Copyright (c) 1987-2012, The Open Group. All rights reserved. * * These libraries and programs are free software; you can * redistribute them and/or modify them under the terms of the GNU * Lesser General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * These libraries and programs are distributed in the hope that * they will be useful, but WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public * License along with these librararies and programs; if not, write * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth * Floor, Boston, MA 02110-1301 USA * */ /* * HISTORY */ /* Ensure that the file be included only once. */ #ifndef _XmdRegEdit_h #define _XmdRegEdit_h #include /* Allow for C++ compilation. */ #ifdef __cplusplus extern "C" { #endif extern void XmdRegisterEditres(Widget toplevel); /* Allow for C++ compilation. */ #ifdef __cplusplus } /* Close scope of 'extern "C"' declaration which encloses file. */ #endif /* Ensure that the file be included only once. */ #endif /* _XmdRegEdit_h */ /* DON'T ADD ANYTHING AFTER THIS #endif */ fbi-2.10/fbtools.c0000644000175000017500000003062312506525033012145 0ustar jmmjmm/* * some generic framebuffer device stuff * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "fbtools.h" #ifndef HAVE_STRSIGNAL static const char *strsignal(int signr) { return sys_siglist[signr]; } #endif /* -------------------------------------------------------------------- */ /* exported stuff */ struct fb_fix_screeninfo fb_fix; struct fb_var_screeninfo fb_var; unsigned char *fb_mem; int fb_mem_offset = 0; int fb_switch_state = FB_ACTIVE; /* -------------------------------------------------------------------- */ /* internal variables */ static int fb,tty; #if 0 static int bpp,black,white; #endif static int orig_vt_no = 0; static struct vt_mode vt_mode; static int kd_mode; static struct vt_mode vt_omode; static struct termios term; static struct fb_var_screeninfo fb_ovar; static unsigned short ored[256], ogreen[256], oblue[256]; static struct fb_cmap ocmap = { 0, 256, ored, ogreen, oblue }; /* -------------------------------------------------------------------- */ /* devices */ struct DEVS { char *fb0; char *fbnr; char *ttynr; }; struct DEVS devs_default = { fb0: "/dev/fb0", fbnr: "/dev/fb%d", ttynr: "/dev/tty%d", }; struct DEVS devs_devfs = { fb0: "/dev/fb/0", fbnr: "/dev/fb/%d", ttynr: "/dev/vc/%d", }; struct DEVS *devices; static void dev_init(void) { struct stat dummy; if (NULL != devices) return; if (0 == stat("/dev/.devfsd",&dummy)) devices = &devs_devfs; else devices = &devs_default; } /* -------------------------------------------------------------------- */ /* console switching */ extern int debug; static void fb_switch_signal(int signal) { if (signal == SIGUSR1) { /* release */ fb_switch_state = FB_REL_REQ; if (debug) write(2,"vt: SIGUSR1\n",12); } if (signal == SIGUSR2) { /* acquisition */ fb_switch_state = FB_ACQ_REQ; if (debug) write(2,"vt: SIGUSR2\n",12); } } void fb_switch_release() { ioctl(tty, VT_RELDISP, 1); fb_switch_state = FB_INACTIVE; if (debug) write(2,"vt: release\n",12); } void fb_switch_acquire() { ioctl(tty, VT_RELDISP, VT_ACKACQ); fb_switch_state = FB_ACTIVE; if (debug) write(2,"vt: acquire\n",12); } int fb_switch_init() { struct sigaction act,old; memset(&act,0,sizeof(act)); act.sa_handler = fb_switch_signal; sigemptyset(&act.sa_mask); sigaction(SIGUSR1,&act,&old); sigaction(SIGUSR2,&act,&old); if (-1 == ioctl(tty,VT_GETMODE, &vt_mode)) { perror("ioctl VT_GETMODE"); exit(1); } vt_mode.mode = VT_PROCESS; vt_mode.waitv = 0; vt_mode.relsig = SIGUSR1; vt_mode.acqsig = SIGUSR2; if (-1 == ioctl(tty,VT_SETMODE, &vt_mode)) { perror("ioctl VT_SETMODE"); exit(1); } return 0; } /* -------------------------------------------------------------------- */ /* initialisation & cleanup */ void fb_memset (void *addr, int c, size_t len) { #if 1 /* defined(__powerpc__) */ unsigned int i, *p; i = (c & 0xff) << 8; i |= i << 16; len >>= 2; for (p = addr; len--; p++) *p = i; #else memset(addr, c, len); #endif } static int fb_setmode(char *name) { FILE *fp; char line[80],label[32],value[16]; int geometry=0, timings=0; /* load current values */ if (-1 == ioctl(fb,FBIOGET_VSCREENINFO,&fb_var)) { perror("ioctl FBIOGET_VSCREENINFO"); exit(1); } if (NULL == name) return -1; if (NULL == (fp = fopen("/etc/fb.modes","r"))) return -1; while (NULL != fgets(line,79,fp)) { if (1 == sscanf(line, "mode \"%31[^\"]\"",label) && 0 == strcmp(label,name)) { /* fill in new values */ fb_var.sync = 0; fb_var.vmode = 0; while (NULL != fgets(line,79,fp) && NULL == strstr(line,"endmode")) { if (5 == sscanf(line," geometry %d %d %d %d %d", &fb_var.xres,&fb_var.yres, &fb_var.xres_virtual,&fb_var.yres_virtual, &fb_var.bits_per_pixel)) geometry = 1; if (7 == sscanf(line," timings %d %d %d %d %d %d %d", &fb_var.pixclock, &fb_var.left_margin, &fb_var.right_margin, &fb_var.upper_margin, &fb_var.lower_margin, &fb_var.hsync_len, &fb_var.vsync_len)) timings = 1; if (1 == sscanf(line, " hsync %15s",value) && 0 == strcasecmp(value,"high")) fb_var.sync |= FB_SYNC_HOR_HIGH_ACT; if (1 == sscanf(line, " vsync %15s",value) && 0 == strcasecmp(value,"high")) fb_var.sync |= FB_SYNC_VERT_HIGH_ACT; if (1 == sscanf(line, " csync %15s",value) && 0 == strcasecmp(value,"high")) fb_var.sync |= FB_SYNC_COMP_HIGH_ACT; if (1 == sscanf(line, " extsync %15s",value) && 0 == strcasecmp(value,"true")) fb_var.sync |= FB_SYNC_EXT; if (1 == sscanf(line, " laced %15s",value) && 0 == strcasecmp(value,"true")) fb_var.vmode |= FB_VMODE_INTERLACED; if (1 == sscanf(line, " double %15s",value) && 0 == strcasecmp(value,"true")) fb_var.vmode |= FB_VMODE_DOUBLE; } /* ok ? */ if (!geometry || !timings) return -1; /* set */ fb_var.xoffset = 0; fb_var.yoffset = 0; if (-1 == ioctl(fb,FBIOPUT_VSCREENINFO,&fb_var)) perror("ioctl FBIOPUT_VSCREENINFO"); /* look what we have now ... */ if (-1 == ioctl(fb,FBIOGET_VSCREENINFO,&fb_var)) { perror("ioctl FBIOGET_VSCREENINFO"); exit(1); } return 0; } } return -1; } static void fb_setvt(int vtno) { struct vt_stat vts; char vtname[12]; if (vtno < 0) { if (-1 == ioctl(tty,VT_OPENQRY, &vtno) || vtno == -1) { perror("ioctl VT_OPENQRY"); exit(1); } } vtno &= 0xff; sprintf(vtname, devices->ttynr, vtno); chown(vtname, getuid(), getgid()); if (-1 == access(vtname, R_OK | W_OK)) { fprintf(stderr,"access %s: %s\n",vtname,strerror(errno)); exit(1); } switch (fork()) { case 0: break; case -1: perror("fork"); exit(1); default: exit(0); } close(tty); close(0); close(1); close(2); setsid(); open(vtname,O_RDWR); dup(0); dup(0); if (-1 == ioctl(tty,VT_GETSTATE, &vts)) { perror("ioctl VT_GETSTATE"); exit(1); } orig_vt_no = vts.v_active; if (-1 == ioctl(tty,VT_ACTIVATE, vtno)) { perror("ioctl VT_ACTIVATE"); exit(1); } if (-1 == ioctl(tty,VT_WAITACTIVE, vtno)) { perror("ioctl VT_WAITACTIVE"); exit(1); } } /* Hmm. radeonfb needs this. matroxfb doesn't. */ static int fb_activate_current(int tty) { struct vt_stat vts; if (-1 == ioctl(tty,VT_GETSTATE, &vts)) { perror("ioctl VT_GETSTATE"); return -1; } if (-1 == ioctl(tty,VT_ACTIVATE, vts.v_active)) { perror("ioctl VT_ACTIVATE"); return -1; } if (-1 == ioctl(tty,VT_WAITACTIVE, vts.v_active)) { perror("ioctl VT_WAITACTIVE"); return -1; } return 0; } int fb_init(char *device, char *mode, int vt) { char fbdev[16]; struct vt_stat vts; unsigned long page_mask; dev_init(); tty = 0; if (vt != 0) fb_setvt(vt); if (-1 == ioctl(tty,VT_GETSTATE, &vts)) { fprintf(stderr,"ioctl VT_GETSTATE: %s (not a linux console?)\n", strerror(errno)); exit(1); } if (NULL == device) { device = getenv("FRAMEBUFFER"); if (NULL == device) { struct fb_con2fbmap c2m; memset(&c2m, 0, sizeof(c2m)); if (-1 == (fb = open(devices->fb0,O_RDWR /* O_WRONLY */,0))) { fprintf(stderr,"open %s: %s\n",devices->fb0,strerror(errno)); exit(1); } c2m.console = vts.v_active; if (-1 == ioctl(fb, FBIOGET_CON2FBMAP, &c2m)) { perror("ioctl FBIOGET_CON2FBMAP"); exit(1); } close(fb); fprintf(stderr,"map: vt%02d => fb%d\n", c2m.console, c2m.framebuffer); sprintf(fbdev,devices->fbnr,c2m.framebuffer); device = fbdev; } } /* get current settings (which we have to restore) */ if (-1 == (fb = open(device,O_RDWR /* O_WRONLY */))) { fprintf(stderr,"open %s: %s\n",device,strerror(errno)); exit(1); } if (-1 == ioctl(fb,FBIOGET_VSCREENINFO,&fb_ovar)) { perror("ioctl FBIOGET_VSCREENINFO"); exit(1); } if (-1 == ioctl(fb,FBIOGET_FSCREENINFO,&fb_fix)) { perror("ioctl FBIOGET_FSCREENINFO"); exit(1); } if (fb_ovar.bits_per_pixel == 8 || fb_fix.visual == FB_VISUAL_DIRECTCOLOR) { if (-1 == ioctl(fb,FBIOGETCMAP,&ocmap)) { perror("ioctl FBIOGETCMAP"); exit(1); } } if (-1 == ioctl(tty,KDGETMODE, &kd_mode)) { perror("ioctl KDGETMODE"); exit(1); } if (-1 == ioctl(tty,VT_GETMODE, &vt_omode)) { perror("ioctl VT_GETMODE"); exit(1); } tcgetattr(tty, &term); /* switch mode */ fb_setmode(mode); /* checks & initialisation */ if (-1 == ioctl(fb,FBIOGET_FSCREENINFO,&fb_fix)) { perror("ioctl FBIOGET_FSCREENINFO"); exit(1); } if (fb_fix.type != FB_TYPE_PACKED_PIXELS) { fprintf(stderr,"can handle only packed pixel frame buffers\n"); goto err; } #if 0 switch (fb_var.bits_per_pixel) { case 8: white = 255; black = 0; bpp = 1; break; case 15: case 16: if (fb_var.green.length == 6) white = 0xffff; else white = 0x7fff; black = 0; bpp = 2; break; case 24: white = 0xffffff; black = 0; bpp = fb_var.bits_per_pixel/8; break; case 32: white = 0xffffff; black = 0; bpp = fb_var.bits_per_pixel/8; fb_setpixels = fb_setpixels4; break; default: fprintf(stderr, "Oops: %i bit/pixel ???\n", fb_var.bits_per_pixel); goto err; } #endif page_mask = getpagesize()-1; fb_mem_offset = (unsigned long)(fb_fix.smem_start) & page_mask; fb_mem = mmap(NULL,fb_fix.smem_len+fb_mem_offset, PROT_READ|PROT_WRITE,MAP_SHARED,fb,0); if (-1L == (long)fb_mem) { perror("mmap"); goto err; } /* move viewport to upper left corner */ if (fb_var.xoffset != 0 || fb_var.yoffset != 0) { fb_var.xoffset = 0; fb_var.yoffset = 0; if (-1 == ioctl(fb,FBIOPAN_DISPLAY,&fb_var)) { perror("ioctl FBIOPAN_DISPLAY"); goto err; } } if (-1 == ioctl(tty,KDSETMODE, KD_GRAPHICS)) { perror("ioctl KDSETMODE"); goto err; } fb_activate_current(tty); /* cls */ fb_memset(fb_mem+fb_mem_offset, 0, fb_fix.line_length * fb_var.yres); return fb; err: fb_cleanup(); exit(1); } void fb_cleanup(void) { /* restore console */ if (-1 == ioctl(tty,KDSETMODE, kd_mode)) perror("ioctl KDSETMODE"); if (-1 == ioctl(fb,FBIOPUT_VSCREENINFO,&fb_ovar)) perror("ioctl FBIOPUT_VSCREENINFO"); if (-1 == ioctl(fb,FBIOGET_FSCREENINFO,&fb_fix)) perror("ioctl FBIOGET_FSCREENINFO"); if (fb_ovar.bits_per_pixel == 8 || fb_fix.visual == FB_VISUAL_DIRECTCOLOR) { if (-1 == ioctl(fb,FBIOPUTCMAP,&ocmap)) perror("ioctl FBIOPUTCMAP"); } close(fb); if (-1 == ioctl(tty,VT_SETMODE, &vt_omode)) perror("ioctl VT_SETMODE"); if (orig_vt_no && -1 == ioctl(tty, VT_ACTIVATE, orig_vt_no)) perror("ioctl VT_ACTIVATE"); if (orig_vt_no && -1 == ioctl(tty, VT_WAITACTIVE, orig_vt_no)) perror("ioctl VT_WAITACTIVE"); tcsetattr(tty, TCSANOW, &term); close(tty); } /* -------------------------------------------------------------------- */ /* handle fatal errors */ static jmp_buf fb_fatal_cleanup; static void fb_catch_exit_signal(int signal) { siglongjmp(fb_fatal_cleanup,signal); } void fb_catch_exit_signals(void) { struct sigaction act,old; int termsig; memset(&act,0,sizeof(act)); act.sa_handler = fb_catch_exit_signal; sigemptyset(&act.sa_mask); sigaction(SIGINT, &act,&old); sigaction(SIGQUIT,&act,&old); sigaction(SIGTERM,&act,&old); sigaction(SIGABRT,&act,&old); sigaction(SIGTSTP,&act,&old); sigaction(SIGBUS, &act,&old); sigaction(SIGILL, &act,&old); sigaction(SIGSEGV,&act,&old); if (0 == (termsig = sigsetjmp(fb_fatal_cleanup,0))) return; /* cleanup */ fb_cleanup(); fprintf(stderr,"Oops: %s\n",strsignal(termsig)); exit(42); } fbi-2.10/jpegtools.c0000644000175000017500000004055012506525033012503 0ustar jmmjmm/* * jpegtran.c * * Copyright (C) 1995-1997, Thomas G. Lane. * This file is part of the Independent JPEG Group's software. * For conditions of distribution and use, see the accompanying README file. * * plenty of changes by Gerd Hoffmann , with focus on * digital image processing and sane exif handling: * * - does transformations only (flip/rotate/transpose/transverse). * - also transforms the exif thumbnail if present. * - can automatically figure transformation from the * exif orientation tag. * - updates the exif orientation tag. * - updates the exif pixel dimension tags. * * This file contains a command-line user interface for JPEG transcoding. * It is very similar to cjpeg.c, but provides lossless transcoding between * different JPEG file formats. It also provides some lossless and sort-of- * lossless transformations of JPEG data. */ #include #include #include #include #include #include #include #include #include #include #include #include "transupp.h" /* Support routines for jpegtran */ #include "jpegtools.h" #include "misc.h" #include #include #include #include static int do_transform(struct jpeg_decompress_struct *src, struct jpeg_compress_struct *dst, JXFORM_CODE transform, unsigned char *comment, char *thumbnail, int tsize, unsigned int flags); static JXFORM_CODE transmagic[] = { [ 1 ] = JXFORM_NONE, [ 2 ] = JXFORM_FLIP_H, [ 3 ] = JXFORM_ROT_180, [ 4 ] = JXFORM_FLIP_V, [ 5 ] = JXFORM_TRANSPOSE, [ 6 ] = JXFORM_ROT_90, [ 7 ] = JXFORM_TRANSVERSE, [ 8 ] = JXFORM_ROT_270, }; #if 0 static char *transname[] = { [ JXFORM_NONE ] = "none", [ JXFORM_FLIP_H ] = "flip h", [ JXFORM_FLIP_V ] = "flip v", [ JXFORM_TRANSPOSE ] = "transpose", [ JXFORM_TRANSVERSE ] = "transverse", [ JXFORM_ROT_90 ] = "rot 90", [ JXFORM_ROT_180 ] = "rot 190", [ JXFORM_ROT_270 ] = "rot 270", }; #endif /* ---------------------------------------------------------------------- */ /* libjpeg error handler -- exit via longjump */ struct longjmp_error_mgr { struct jpeg_error_mgr jpeg; jmp_buf setjmp_buffer; }; static void longjmp_error_exit(j_common_ptr cinfo) { struct longjmp_error_mgr *h = (struct longjmp_error_mgr*)cinfo->err; (*cinfo->err->output_message)(cinfo); longjmp(h->setjmp_buffer, 1); } /* ---------------------------------------------------------------------- */ static long get_int(ExifData *ed, ExifEntry *ee) { ExifByteOrder o = exif_data_get_byte_order(ed); long value; switch (ee->format) { case EXIF_FORMAT_SHORT: value = exif_get_short (ee->data, o); break; case EXIF_FORMAT_LONG: value = exif_get_long (ee->data, o); break; case EXIF_FORMAT_SLONG: value = exif_get_slong (ee->data, o); break; default: fprintf(stderr,"get_int oops\n"); exit(1); } return value; } static void set_int(ExifData *ed, ExifEntry *ee, long value) { ExifByteOrder o = exif_data_get_byte_order(ed); switch (ee->format) { case EXIF_FORMAT_SHORT: exif_set_short (ee->data, o, value); break; case EXIF_FORMAT_LONG: exif_set_long (ee->data, o, value); break; case EXIF_FORMAT_SLONG: exif_set_slong (ee->data, o, value); break; default: fprintf(stderr,"set_int oops\n"); exit(1); } } static void update_orientation(ExifData *ed, int ifd, int orientation) { ExifEntry *ee; ee = exif_content_get_entry(ed->ifd[ifd], 0x0112); if (NULL == ee) return; set_int(ed,ee,orientation); } static void update_dimension(ExifData *ed, JXFORM_CODE transform, int src_x, int src_y) { static struct { int idf; int tag; int x; } fields[] = { { .idf = EXIF_IFD_EXIF, .tag = EXIF_TAG_PIXEL_X_DIMENSION, .x = 1, },{ .idf = EXIF_IFD_EXIF, .tag = EXIF_TAG_PIXEL_Y_DIMENSION, .x = 0, },{ .idf = EXIF_IFD_INTEROPERABILITY, .tag = EXIF_TAG_RELATED_IMAGE_WIDTH, .x = 1, },{ .idf = EXIF_IFD_INTEROPERABILITY, .tag = EXIF_TAG_RELATED_IMAGE_LENGTH, .x = 0, } }; ExifEntry *ee; int i; for (i = 0; i < sizeof(fields)/sizeof(fields[0]); i++) { ee = exif_content_get_entry(ed->ifd[fields[i].idf], fields[i].tag); if (!ee) continue; switch (transform) { case JXFORM_ROT_90: case JXFORM_ROT_270: case JXFORM_TRANSPOSE: case JXFORM_TRANSVERSE: /* x/y reversed */ set_int(ed, ee, fields[i].x ? src_y : src_x); break; default: /* normal */ set_int(ed, ee, fields[i].x ? src_x : src_y); break; } } } static int get_orientation(ExifData *ed) { ExifEntry *ee; ee = exif_content_get_entry(ed->ifd[EXIF_IFD_0], 0x0112); if (NULL == ee) return 1; /* top - left */ return get_int(ed,ee); } static int get_file_orientation(const char *file) { ExifData *ed; int ret; ed = exif_data_new_from_file(file); ret = ed ? get_orientation(ed) : 1 /* top - left */; exif_data_unref(ed); return ret; } /* ---------------------------------------------------------------------- */ struct th { struct jpeg_decompress_struct src; struct jpeg_compress_struct dst; struct jpeg_error_mgr jsrcerr, jdsterr; unsigned char *in; unsigned char *out; int isize, osize; }; static void thumbnail_src_init(struct jpeg_decompress_struct *cinfo) { struct th *h = container_of(cinfo, struct th, src); cinfo->src->next_input_byte = h->in; cinfo->src->bytes_in_buffer = h->isize; } static int thumbnail_src_fill(struct jpeg_decompress_struct *cinfo) { fprintf(stderr,"jpeg: panic: no more thumbnail input data\n"); exit(1); } static void thumbnail_src_skip(struct jpeg_decompress_struct *cinfo, long num_bytes) { cinfo->src->next_input_byte += num_bytes; } static void thumbnail_src_term(struct jpeg_decompress_struct *cinfo) { /* nothing */ } static void thumbnail_dest_init(struct jpeg_compress_struct *cinfo) { struct th *h = container_of(cinfo, struct th, dst); h->osize = h->isize * 2; h->out = malloc(h->osize); cinfo->dest->next_output_byte = h->out; cinfo->dest->free_in_buffer = h->osize; } static boolean thumbnail_dest_flush(struct jpeg_compress_struct *cinfo) { fprintf(stderr,"jpeg: panic: output buffer full\n"); exit(1); } static void thumbnail_dest_term(struct jpeg_compress_struct *cinfo) { struct th *h = container_of(cinfo, struct th, dst); h->osize -= cinfo->dest->free_in_buffer; } static struct jpeg_source_mgr thumbnail_src = { .init_source = thumbnail_src_init, .fill_input_buffer = thumbnail_src_fill, .skip_input_data = thumbnail_src_skip, .resync_to_restart = jpeg_resync_to_restart, .term_source = thumbnail_src_term, }; static struct jpeg_destination_mgr thumbnail_dst = { .init_destination = thumbnail_dest_init, .empty_output_buffer = thumbnail_dest_flush, .term_destination = thumbnail_dest_term, }; static void do_thumbnail(ExifData *ed, JXFORM_CODE transform) { struct th th; if (JXFORM_NONE == transform) return; memset(&th,0,sizeof(th)); th.in = ed->data; th.isize = ed->size; /* setup src */ th.src.err = jpeg_std_error(&th.jsrcerr); jpeg_create_decompress(&th.src); th.src.src = &thumbnail_src; /* setup dst */ th.dst.err = jpeg_std_error(&th.jdsterr); jpeg_create_compress(&th.dst); th.dst.dest = &thumbnail_dst; /* transform image */ do_transform(&th.src,&th.dst,transform,NULL,NULL,0,JFLAG_TRANSFORM_IMAGE); /* cleanup */ jpeg_destroy_decompress(&th.src); jpeg_destroy_compress(&th.dst); /* replace thumbnail */ free(ed->data); ed->data = th.out; ed->size = th.osize; } static void do_exif(struct jpeg_decompress_struct *src, JXFORM_CODE *transform, char *thumbnail, int tsize, unsigned int flags) { jpeg_saved_marker_ptr mark; ExifData *ed = NULL; unsigned char *data; unsigned int size; for (mark = src->marker_list; NULL != mark; mark = mark->next) { if (mark->marker != JPEG_APP0 +1) continue; ed = exif_data_new_from_data(mark->data,mark->data_length); break; } if (flags & JFLAG_UPDATE_THUMBNAIL) { if (NULL == ed) ed = exif_data_new(); if (NULL == mark) { mark = src->mem->alloc_large((j_common_ptr)src,JPOOL_IMAGE,sizeof(*mark)); memset(mark,0,sizeof(*mark)); mark->marker = JPEG_APP0 +1; mark->next = src->marker_list; src->marker_list = mark; } if (ed->data) free(ed->data); ed->data = thumbnail; ed->size = tsize; } if (NULL == ed) return; if (-1 == *transform) { /* automagic image transformation */ int orientation = get_orientation(ed); *transform = JXFORM_NONE; if (orientation >= 1 && orientation <= 8) *transform = transmagic[orientation]; #if 0 if (debug) fprintf(stderr,"autotrans: %s\n",transname[*transform]); #endif } /* update exif data */ if (flags & JFLAG_UPDATE_ORIENTATION) { update_orientation(ed,EXIF_IFD_0,1); update_orientation(ed,EXIF_IFD_1,1); } if (ed->data && ed->data[0] == 0xff && ed->data[1] == 0xd8 && (flags & JFLAG_TRANSFORM_THUMBNAIL)) do_thumbnail(ed,*transform); update_dimension(ed, (flags & JFLAG_TRANSFORM_IMAGE) ? *transform : JXFORM_NONE, src->image_width, src->image_height); /* build new exif data block */ exif_data_save_data(ed,&data,&size); exif_data_unref(ed); /* update jpeg APP1 (EXIF) marker */ mark->data = src->mem->alloc_large((j_common_ptr)src,JPOOL_IMAGE,size); mark->original_length = size; mark->data_length = size; memcpy(mark->data,data,size); free(data); } /* ---------------------------------------------------------------------- */ static void do_comment(struct jpeg_decompress_struct *src, unsigned char *comment) { jpeg_saved_marker_ptr mark; int size; /* find or create comment marker */ for (mark = src->marker_list;; mark = mark->next) { if (mark->marker == JPEG_COM) break; if (NULL == mark->next) { mark->next = src->mem->alloc_large((j_common_ptr)src,JPOOL_IMAGE, sizeof(*mark)); mark = mark->next; memset(mark,0,sizeof(*mark)); mark->marker = JPEG_COM; break; } } /* update comment marker */ size = strlen(comment) +1; mark->data = src->mem->alloc_large((j_common_ptr)src,JPOOL_IMAGE,size); mark->original_length = size; mark->data_length = size; memcpy(mark->data,comment,size); } static int do_transform(struct jpeg_decompress_struct *src, struct jpeg_compress_struct *dst, JXFORM_CODE transform, unsigned char *comment, char *thumbnail, int tsize, unsigned int flags) { jvirt_barray_ptr * src_coef_arrays; jvirt_barray_ptr * dst_coef_arrays; jpeg_transform_info transformoption; jcopy_markers_setup(src, JCOPYOPT_ALL); if (JPEG_HEADER_OK != jpeg_read_header(src, TRUE)) return -1; do_exif(src,&transform,thumbnail,tsize,flags); if (-1 == transform) transform = JXFORM_NONE; if (!(flags & JFLAG_TRANSFORM_IMAGE)) transform = JXFORM_NONE; if ((flags & JFLAG_UPDATE_COMMENT) && NULL != comment) do_comment(src,comment); memset(&transformoption,0,sizeof(transformoption)); transformoption.transform = transform; if (!(flags & JFLAG_TRANSFORM_TRIM)) transformoption.trim = TRUE; else transformoption.trim = FALSE; transformoption.force_grayscale = FALSE; /* Any space needed by a transform option must be requested before * jpeg_read_coefficients so that memory allocation will be done right. */ jtransform_request_workspace(src, &transformoption); src_coef_arrays = jpeg_read_coefficients(src); jpeg_copy_critical_parameters(src, dst); dst_coef_arrays = jtransform_adjust_parameters (src, dst, src_coef_arrays, &transformoption); /* Start compressor (note no image data is actually written here) */ jpeg_write_coefficients(dst, dst_coef_arrays); /* Copy to the output file any extra markers that we want to preserve */ jcopy_markers_execute(src, dst, JCOPYOPT_ALL); /* Execute image transformation, if any */ jtransform_execute_transformation(src, dst, src_coef_arrays, &transformoption); /* Finish compression and release memory */ jpeg_finish_compress(dst); jpeg_finish_decompress(src); return 0; } /* ---------------------------------------------------------------------- */ int jpeg_transform_fp(FILE *in, FILE *out, JXFORM_CODE transform, unsigned char *comment, char *thumbnail, int tsize, unsigned int flags) { struct jpeg_decompress_struct src; struct jpeg_compress_struct dst; struct jpeg_error_mgr jdsterr; struct longjmp_error_mgr jsrcerr; /* setup src */ src.err = jpeg_std_error(&jsrcerr.jpeg); jsrcerr.jpeg.error_exit = longjmp_error_exit; if (setjmp(jsrcerr.setjmp_buffer)) /* something went wrong within the jpeg library ... */ goto oops; jpeg_create_decompress(&src); jpeg_stdio_src(&src, in); /* setup dst */ dst.err = jpeg_std_error(&jdsterr); jpeg_create_compress(&dst); jpeg_stdio_dest(&dst, out); /* transform image */ do_transform(&src,&dst,transform,comment,thumbnail,tsize,flags); /* cleanup */ jpeg_destroy_decompress(&src); jpeg_destroy_compress(&dst); return 0; oops: jpeg_destroy_decompress(&src); jpeg_destroy_compress(&dst); return -1; } int jpeg_transform_files(char *infile, char *outfile, JXFORM_CODE transform, unsigned char *comment, char *thumbnail, int tsize, unsigned int flags) { int rc; FILE *in; FILE *out; /* open infile */ in = fopen(infile,"r"); if (NULL == in) { fprintf(stderr,"open %s: %s\n",infile,strerror(errno)); return -1; } /* open outfile */ out = fopen(outfile,"w"); if (NULL == out) { fprintf(stderr,"open %s: %s\n",outfile,strerror(errno)); fclose(in); return -1; } /* go! */ rc = jpeg_transform_fp(in,out,transform,comment,thumbnail,tsize,flags); fclose(in); fclose(out); return rc; } int jpeg_transform_inplace(char *file, JXFORM_CODE transform, unsigned char *comment, char *thumbnail, int tsize, unsigned int flags) { char *tmpfile; char *bakfile; struct stat st; int fd; FILE *in = NULL; FILE *out = NULL; /* are we allowed to write to the file? */ if (0 != access(file, R_OK | W_OK)) { fprintf(stderr,"access %s: %s\n",file,strerror(errno)); return -1; } if (!(flags & JFLAG_UPDATE_COMMENT) && !(flags & JFLAG_UPDATE_THUMBNAIL)) { /* no forced updates, maybe we can shortcut here? */ if (transform == JXFORM_NONE) return 0; if (transform == -1 && get_file_orientation(file) == 1) return 0; } /* open infile */ in = fopen(file,"r"); if (NULL == in) { fprintf(stderr,"open %s: %s\n",file,strerror(errno)); return -1; } /* open tmpfile */ tmpfile = malloc(strlen(file)+10); sprintf(tmpfile,"%s.XXXXXX",file); fd = mkstemp(tmpfile); if (-1 == fd) { fprintf(stderr,"mkstemp(%s): %s\n",tmpfile,strerror(errno)); goto oops; } out = fdopen(fd,"w"); /* copy owner and permissions */ if (-1 == fstat(fileno(in),&st)) { fprintf(stderr,"fstat(%s): %s\n",file,strerror(errno)); goto oops; } if (-1 == fchown(fileno(out),st.st_uid,st.st_gid)) { fprintf(stderr,"fchown(%s): %s\n",tmpfile,strerror(errno)); goto oops; } if (-1 == fchmod(fileno(out),st.st_mode)) { fprintf(stderr,"fchmod(%s): %s\n",tmpfile,strerror(errno)); goto oops; } /* transform */ if (0 != jpeg_transform_fp(in,out,transform,comment,thumbnail,tsize,flags)) goto oops; /* worked ok -- commit */ fclose(in); fclose(out); if (flags & JFLAG_FILE_BACKUP) { bakfile = malloc(strlen(file)+2); sprintf(bakfile,"%s~",file); rename(file,bakfile); free(bakfile); } rename(tmpfile,file); if (flags & JFLAG_FILE_KEEP_TIME) { struct utimbuf u; u.actime = st.st_atime; u.modtime = st.st_mtime; utime(file,&u); } /* cleanup & return */ free(tmpfile); return 0; oops: /* something went wrong -- rollback */ if (in) fclose(in); if (out) { fclose(out); unlink(tmpfile); } return -1; } fbi-2.10/hex.c0000644000175000017500000000703012506525033011255 0ustar jmmjmm/* * file viewer (hex dump) * quick & dirty for now, handling xxl files doesn't work very well ... * * (c) 2001 Gerd Hoffmann * */ #include #include #include #include #include #include #include #include #include #include #include #include #include "RegEdit.h" #include "hex.h" extern Display *dpy; extern Widget app_shell; /*----------------------------------------------------------------------*/ static Widget hex_dlg, hex_label; static void hex_destroy(Widget widget, XtPointer clientdata, XtPointer call_data) { XtDestroyWidget(hex_dlg); hex_dlg = NULL; } static XmString hexify(int addr,unsigned char *data, int bytes) { XmString xmpage,xmchunk; char line[120]; int len,y,i; xmpage = XmStringGenerate("", NULL, XmMULTIBYTE_TEXT, NULL); for (y = 0; y < bytes; y += 16) { /* hexify line */ len = sprintf(line,"%04x ",addr+y); for (i = 0; i < 16; i++) { if (y+i < bytes) len += sprintf(line+len,"%02x ",data[y+i]); else len += sprintf(line+len," "); if (3 == i%4) len += sprintf(line+len," "); } for (i = 0; i < 16; i++) { if (y+i < bytes) if (isprint(data[y+i])) len += sprintf(line+len,"%c",data[y+i]); else len += sprintf(line+len,"."); else len += sprintf(line+len," "); } len += sprintf(line+len,"\n"); /* add last chunk for line */ xmchunk = XmStringGenerate(line, NULL, XmMULTIBYTE_TEXT, NULL); xmpage = XmStringConcatAndFree(xmpage, xmchunk); } return xmpage; } /* guess whenever we have ascii or binary data */ static int is_binary(unsigned char *data, int bytes) { int i, bin; bin = 0; for (i = 0; i < 64 && i < bytes; i++) { if (!isprint(data[i]) && data[i] != '\t' && data[i] != '\n') bin = 1; } return bin; } void hex_display(char *filename) { Widget view; XmString xmpage,chunk; unsigned char data[32768+1]; int chars; FILE *fp; /* build dialog */ if (!hex_dlg) { hex_dlg = XmCreatePromptDialog(app_shell,"hex",NULL,0); XmdRegisterEditres(XtParent(hex_dlg)); XtUnmanageChild(XmSelectionBoxGetChild(hex_dlg, XmDIALOG_SELECTION_LABEL)); XtUnmanageChild(XmSelectionBoxGetChild(hex_dlg,XmDIALOG_HELP_BUTTON)); XtUnmanageChild(XmSelectionBoxGetChild(hex_dlg, XmDIALOG_CANCEL_BUTTON)); XtUnmanageChild(XmSelectionBoxGetChild(hex_dlg,XmDIALOG_TEXT)); XtAddCallback(hex_dlg,XmNokCallback,hex_destroy,NULL); view = XmCreateScrolledWindow(hex_dlg,"view",NULL,0); XtManageChild(view); hex_label = XtVaCreateManagedWidget("label", xmLabelWidgetClass, view, NULL); } XtManageChild(hex_dlg); /* read the file (32k max) */ fp = fopen(filename,"r"); memset(data,0,sizeof(data)); chars = fread(data, 1, sizeof(data)-1, fp); if (is_binary(data,chars)) { xmpage = hexify(0, data, chars); if (sizeof(data)-1 == chars) { chunk = XmStringGenerate("[ ... ]\n",NULL, XmMULTIBYTE_TEXT, NULL); xmpage = XmStringConcatAndFree(xmpage,chunk); } } else { xmpage = XmStringGenerate(data, NULL, XmMULTIBYTE_TEXT, NULL); if (sizeof(data)-1 == chars) { chunk = XmStringGenerate("\n[ ... ]\n",NULL, XmMULTIBYTE_TEXT, NULL); xmpage = XmStringConcatAndFree(xmpage,chunk); } } XtVaSetValues(hex_label,XmNlabelString,xmpage,NULL); XmStringFree(xmpage); XtVaSetValues(XtParent(hex_dlg),XmNtitle,filename,NULL); fclose(fp); } fbi-2.10/idaconfig.c0000644000175000017500000000177612506525033012427 0ustar jmmjmm#include #include #include #include #include #include #include "idaconfig.h" char *ida_lists; static char *ida_config; void ida_init_config(void) { char *home; char *conf; struct stat st; home = getenv("HOME"); if (NULL == home) return; conf = malloc(strlen(home) + 16); ida_lists = malloc(strlen(home) + 16); ida_config = malloc(strlen(home) + 16); sprintf(conf, "%s/.ida", home); sprintf(ida_lists, "%s/.ida/lists", home); sprintf(ida_config,"%s/.ida/config", home); if (-1 == stat(ida_lists,&st)) { if (-1 == stat(conf,&st)) mkdir(conf,0777); mkdir(ida_lists,0777); } free(conf); } void ida_read_config(void) { int rc; rc = cfg_parse_file("config", ida_config); if (-1 == rc) { /* set some defaults */ cfg_set_str(O_BOOKMARKS, "Home", getenv("HOME")); } } void ida_write_config(void) { cfg_write_file("config", ida_config); } fbi-2.10/lirc.c0000644000175000017500000000237112506525033011425 0ustar jmmjmm#include #include #include #include #include #include #include #include #include #include "lirc.h" /*-----------------------------------------------------------------------*/ static int debug = 0; static struct lirc_config *config = NULL; int lirc_fbi_init() { int fd; if (-1 == (fd = lirc_init("fbi",debug))) { if (debug) fprintf(stderr,"lirc: no infrared remote support available\n"); return -1; } if (0 != lirc_readconfig(NULL,&config,NULL)) { config = NULL; } if (debug) fprintf(stderr, "lirc: ~/.lircrc file %sfound\n", config ? "" : "not "); fcntl(fd,F_SETFL,O_NONBLOCK); fcntl(fd,F_SETFD,FD_CLOEXEC); if (debug) fprintf(stderr,"lirc: init ok\n"); return fd; } int lirc_fbi_havedata(int* rc, char key[11]) { char *code,*cmd; int ret=-1; while (lirc_nextcode(&code) == 0 && code != NULL) { ret = 0; if (config) { /* use ~/.lircrc */ while (lirc_code2char(config,code,&cmd)==0 && cmd != NULL) { memset(key,0,11); strncpy(key,cmd,10); *rc = strlen(cmd); if (debug) fprintf(stderr,"lirc: cmd \"%s\"\n", cmd); } } free(code); } return ret; } fbi-2.10/exiftran.man0000644000175000017500000000740212506525033012645 0ustar jmmjmm.TH EXIFTRAN 1 "(c) 2002-2012 Gerd Hoffmann" "EXIFTRAN 2.09" "Transform digital camera jpeg images" \# \# .SH NAME exiftran - transform digital camera jpeg images \# \# .SH SYNOPSIS .TP \fBexiftran\fP [\fIoptions\fP] \fIfile1 file2 ... fileN\fP .TP \fBexiftran\fP -i [\fItransform options\fP] [\fIothers options\fP] \fIfile1 file2 ... fileN\fP .TP \fBexiftran\fP -o \fIoutputfile\fP [\fItransform options\fP] [\fIother options\fP] \fIinputfile\fP .TP \fBexiftran\fP -d \fIfile1 file2 ... fileN\fP > \fIexifinfo\fP \# \# .SH DESCRIPTION .BR Exiftran is a command line utility to transform digital camera \fIjpeg\fP images. It can do lossless rotations like .BR "jpegtran" "(1)," but unlike .BR "jpegtran" "(1)" it cares about the \fIEXIF\fP data: It can rotate images automatically by checking the exif orientation tag; it updates the exif informations if needed (image dimension, orientation); it also rotates the exif thumbnail. It can process multiple images at once. \# \# .SH "TRANSFORM OPTIONS" .TP .B -a Automatic (using exif orientation tag). .TP .B -9 Rotate by 90 degrees clockwise. .TP .B -1 Rotate by 180 degrees clockwise. .TP .B -2 Rotate by 270 degrees clockwise. .TP .B -f Mirror image vertically (top / bottom). .TP .B -F Mirror image horizontally (left to right). .TP .B -t Transpose (across UL-to-LR corner). .TP .B -T Transverse (across UR-to-LL corner). .TP .B -nt Don't transform exif thumbnail. .TP .B -ni Don't transform jpeg image. You might need this or the \fB-nt\fP option to fixup things in case you transformed the image with some utility which ignores the exif thumbnail. Just generating a new thumbnail with \fB-g\fP is another way to fix it. .TP .B -no Don't update the orientation tag. By default .BR exiftran sets the orientation to "1" (no transformation needed) to avoid other exif-aware applications try to rotate the already-rotated image again. .TP .B -np Don't pare lost edges. By default .BR exiftran don't preserve image size of the images that do not meet a multiple of 8 pixels. He prefers to cut a strip of a few pixels rather than offering a damaged image. Use this option if you want them all the same. \# \# .SH "OTHER OPTIONS" .TP .B -h Print a short help text. .TP .B -d Dump exif data for the file(s). .TP .BI "-c" "\ text" Set jpeg comment tag to \fItext\fP. .TP .B -g (re)generate exif thumbnail. .TP .BI "-o" "\ file" Specify output \fIfile\fP. Only one input file is allowed in this mode. .TP .B -i Enable in-place editing of the images. .BR Exiftran allows multiple input files then. You must specify either this option or a output file with \fB-o\fP for all operations which modify the image (i.e. everything but \fB-d\fP right now). .TP .B -b Create a backup file when doing in-place editing (imply \fB-i\fP). .TP .B -p Preserve timestamps (atime + mtime) when doing in-place editing (imply \fB-i\fP). \# \# .SH EXAMPLES Autorotate all jpeg files in the current directory: .P .in +4n \fIexiftran\ -ai\ *.jpeg\fP .in \# \# .SH "SEE ALSO" .BR exif (1), .BR exiftags (1), .BR jpegtran (1) \# \# .SH AUTHOR Gerd Hoffmann .BR \# \# .SH COPYRIGHT Copyright (c) 2002-2012 Gerd Hoffmann .P 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. .P 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. .P 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., 675 Mass Ave, Cambridge, MA 02139, USA. fbi-2.10/curl.h0000644000175000017500000000020712506525033011442 0ustar jmmjmm#ifdef HAVE_LIBCURL extern int curl_is_url(const char *url); #else static inline int curl_is_url(const char *url) { return 0; } #endif fbi-2.10/op.c0000644000175000017500000001520012506525033011105 0ustar jmmjmm#include #include #include #include #include "readers.h" #include "op.h" #include "filter.h" /* ----------------------------------------------------------------------- */ /* functions */ static char op_none_data; static void op_flip_vert(struct ida_image *src, struct ida_rect *rect, unsigned char *dst, int line, void *data) { char *scanline; scanline = src->data + (src->i.height - line - 1) * src->i.width * 3; memcpy(dst,scanline,src->i.width*3); } static void op_flip_horz(struct ida_image *src, struct ida_rect *rect, unsigned char *dst, int line, void *data) { char *scanline; unsigned int i; scanline = src->data + (line+1) * src->i.width * 3; for (i = 0; i < src->i.width; i++) { scanline -= 3; dst[0] = scanline[0]; dst[1] = scanline[1]; dst[2] = scanline[2]; dst += 3; } } static void* op_rotate_init(struct ida_image *src, struct ida_rect *rect, struct ida_image_info *i, void *parm) { *i = src->i; i->height = src->i.width; i->width = src->i.height; i->dpi = src->i.dpi; return &op_none_data; } static void op_rotate_cw(struct ida_image *src, struct ida_rect *rect, unsigned char *dst, int line, void *data) { char *pix; unsigned int i; pix = src->data + src->i.width * src->i.height * 3 + line * 3; for (i = 0; i < src->i.height; i++) { pix -= src->i.width * 3; dst[0] = pix[0]; dst[1] = pix[1]; dst[2] = pix[2]; dst += 3; } } static void op_rotate_ccw(struct ida_image *src, struct ida_rect *rect, unsigned char *dst, int line, void *data) { char *pix; unsigned int i; pix = src->data + (src->i.width-line-1) * 3; for (i = 0; i < src->i.height; i++) { dst[0] = pix[0]; dst[1] = pix[1]; dst[2] = pix[2]; pix += src->i.width * 3; dst += 3; } } static void op_invert(struct ida_image *src, struct ida_rect *rect, unsigned char *dst, int line, void *data) { unsigned char *scanline; int i; scanline = src->data + line * src->i.width * 3; memcpy(dst,scanline,src->i.width * 3); if (line < rect->y1 || line >= rect->y2) return; dst += 3*rect->x1; scanline += 3*rect->x1; for (i = rect->x1; i < rect->x2; i++) { dst[0] = 255-scanline[0]; dst[1] = 255-scanline[1]; dst[2] = 255-scanline[2]; scanline += 3; dst += 3; } } static void* op_crop_init(struct ida_image *src, struct ida_rect *rect, struct ida_image_info *i, void *parm) { if (rect->x2 - rect->x1 == src->i.width && rect->y2 - rect->y1 == src->i.height) return NULL; *i = src->i; i->width = rect->x2 - rect->x1; i->height = rect->y2 - rect->y1; return &op_none_data; } static void op_crop_work(struct ida_image *src, struct ida_rect *rect, unsigned char *dst, int line, void *data) { unsigned char *scanline; int i; scanline = src->data + (line+rect->y1) * src->i.width * 3 + rect->x1 * 3; for (i = rect->x1; i < rect->x2; i++) { dst[0] = scanline[0]; dst[1] = scanline[1]; dst[2] = scanline[2]; scanline += 3; dst += 3; } } static void* op_autocrop_init(struct ida_image *src, struct ida_rect *unused, struct ida_image_info *i, void *parm) { static struct op_3x3_parm filter = { f1: { -1, -1, -1 }, f2: { -1, 8, -1 }, f3: { -1, -1, -1 }, }; struct ida_rect rect; struct ida_image img; int x,y,limit; unsigned char *line; void *data; /* detect edges */ rect.x1 = 0; rect.x2 = src->i.width; rect.y1 = 0; rect.y2 = src->i.height; data = desc_3x3.init(src, &rect, &img.i, &filter); img.data = malloc(img.i.width * img.i.height * 3); for (y = 0; y < (int)img.i.height; y++) desc_3x3.work(src, &rect, img.data+3*img.i.width*y, y, data); desc_3x3.done(data); limit = 64; /* y border */ for (y = 0; y < (int)img.i.height; y++) { line = img.data + img.i.width*y*3; for (x = 0; x < (int)img.i.width; x++) if (line[3*x+0] > limit || line[3*x+1] > limit || line[3*x+2] > limit) break; if (x != (int)img.i.width) break; } rect.y1 = y; for (y = (int)img.i.height-1; y > rect.y1; y--) { line = img.data + img.i.width*y*3; for (x = 0; x < (int)img.i.width; x++) if (line[3*x+0] > limit || line[3*x+1] > limit || line[3*x+2] > limit) break; if (x != (int)img.i.width) break; } rect.y2 = y+1; /* x border */ for (x = 0; x < (int)img.i.width; x++) { for (y = 0; y < (int)img.i.height; y++) { line = img.data + (img.i.width*y+x) * 3; if (line[0] > limit || line[1] > limit || line[2] > limit) break; } if (y != (int)img.i.height) break; } rect.x1 = x; for (x = (int)img.i.width-1; x > rect.x1; x--) { for (y = 0; y < (int)img.i.height; y++) { line = img.data + (img.i.width*y+x) * 3; if (line[0] > limit || line[1] > limit || line[2] > limit) break; } if (y != (int)img.i.height) break; } rect.x2 = x+1; free(img.data); if (debug) fprintf(stderr,"y: %d-%d/%u -- x: %d-%d/%u\n", rect.y1, rect.y2, img.i.height, rect.x1, rect.x2, img.i.width); if (0 == rect.x2 - rect.x1 || 0 == rect.y2 - rect.y1) return NULL; *unused = rect; *i = src->i; i->width = rect.x2 - rect.x1; i->height = rect.y2 - rect.y1; return &op_none_data; } /* ----------------------------------------------------------------------- */ static char op_none_data; void* op_none_init(struct ida_image *src, struct ida_rect *sel, struct ida_image_info *i, void *parm) { *i = src->i; return &op_none_data; } void op_none_done(void *data) {} void op_free_done(void *data) { free(data); } /* ----------------------------------------------------------------------- */ struct ida_op desc_flip_vert = { name: "flip-vert", init: op_none_init, work: op_flip_vert, done: op_none_done, }; struct ida_op desc_flip_horz = { name: "flip-horz", init: op_none_init, work: op_flip_horz, done: op_none_done, }; struct ida_op desc_rotate_cw = { name: "rotate-cw", init: op_rotate_init, work: op_rotate_cw, done: op_none_done, }; struct ida_op desc_rotate_ccw = { name: "rotate-ccw", init: op_rotate_init, work: op_rotate_ccw, done: op_none_done, }; struct ida_op desc_invert = { name: "invert", init: op_none_init, work: op_invert, done: op_none_done, }; struct ida_op desc_crop = { name: "crop", init: op_crop_init, work: op_crop_work, done: op_none_done, }; struct ida_op desc_autocrop = { name: "autocrop", init: op_autocrop_init, work: op_crop_work, done: op_none_done, }; fbi-2.10/VERSION0000644000175000017500000000000512506525033011370 0ustar jmmjmm2.09 fbi-2.10/fbtools.h0000644000175000017500000000123012506525033012142 0ustar jmmjmm#define FB_ACTIVE 0 #define FB_REL_REQ 1 #define FB_INACTIVE 2 #define FB_ACQ_REQ 3 /* info about videomode - yes I know, quick & dirty... */ extern struct fb_fix_screeninfo fb_fix; extern struct fb_var_screeninfo fb_var; extern unsigned char *fb_mem; extern int fb_mem_offset; extern int fb_switch_state; /* init + cleanup */ int fb_probe(void); int fb_init(char *device, char *mode, int vt); void fb_cleanup(void); void fb_catch_exit_signals(void); void fb_memset(void *addr, int c, size_t len); /* console switching */ int fb_switch_init(void); void fb_switch_release(void); void fb_switch_acquire(void); fbi-2.10/xwd.h0000644000175000017500000000007012506525033011275 0ustar jmmjmmvoid parse_ximage(struct ida_image *dest, XImage *src); fbi-2.10/list.h0000644000175000017500000001043112506525033011450 0ustar jmmjmm#ifndef _LIST_H_ #define _LIST_H_ /* * Simple doubly linked list implementation. * -- shameless stolen from the linux kernel sources * * Some of the internal functions ("__xxx") are useful when * manipulating whole lists rather than single entries, as * sometimes we already know the next/prev entries and we can * generate better code by using them directly rather than * using the generic single-entry routines. */ struct list_head { struct list_head *next, *prev; }; #define LIST_HEAD_INIT(name) { &(name), &(name) } #define LIST_HEAD(name) \ struct list_head name = LIST_HEAD_INIT(name) #define INIT_LIST_HEAD(ptr) do { \ (ptr)->next = (ptr); (ptr)->prev = (ptr); \ } while (0) /* * Insert a new entry between two known consecutive entries. * * This is only for internal list manipulation where we know * the prev/next entries already! */ static __inline__ void __list_add(struct list_head * new, struct list_head * prev, struct list_head * next) { next->prev = new; new->next = next; new->prev = prev; prev->next = new; } /** * list_add - add a new entry * @new: new entry to be added * @head: list head to add it after * * Insert a new entry after the specified head. * This is good for implementing stacks. */ static __inline__ void list_add(struct list_head *new, struct list_head *head) { __list_add(new, head, head->next); } /** * list_add_tail - add a new entry * @new: new entry to be added * @head: list head to add it before * * Insert a new entry before the specified head. * This is useful for implementing queues. */ static __inline__ void list_add_tail(struct list_head *new, struct list_head *head) { __list_add(new, head->prev, head); } /* * Delete a list entry by making the prev/next entries * point to each other. * * This is only for internal list manipulation where we know * the prev/next entries already! */ static __inline__ void __list_del(struct list_head * prev, struct list_head * next) { next->prev = prev; prev->next = next; } /** * list_del - deletes entry from list. * @entry: the element to delete from the list. * Note: list_empty on entry does not return true after this, the entry is in an undefined state. */ static __inline__ void list_del(struct list_head *entry) { __list_del(entry->prev, entry->next); } /** * list_del_init - deletes entry from list and reinitialize it. * @entry: the element to delete from the list. */ static __inline__ void list_del_init(struct list_head *entry) { __list_del(entry->prev, entry->next); INIT_LIST_HEAD(entry); } /** * list_empty - tests whether a list is empty * @head: the list to test. */ static __inline__ int list_empty(struct list_head *head) { return head->next == head; } /** * list_splice - join two lists * @list: the new list to add. * @head: the place to add it in the first list. */ static __inline__ void list_splice(struct list_head *list, struct list_head *head) { struct list_head *first = list->next; if (first != list) { struct list_head *last = list->prev; struct list_head *at = head->next; first->prev = head; head->next = first; last->next = at; at->prev = last; } } /** * list_entry - get the struct for this entry * @ptr: the &struct list_head pointer. * @type: the type of the struct this is embedded in. * @member: the name of the list_struct within the struct. */ #define list_entry(ptr, type, member) \ ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member))) /** * list_for_each - iterate over a list * @pos: the &struct list_head to use as a loop counter. * @head: the head for your list. */ #define list_for_each(pos, head) \ for (pos = (head)->next; pos != (head); pos = pos->next) /** * list_for_each_safe - iterate over a list safe against removal of list entry * @pos: the &struct list_head to use as a loop counter. * @n: another &struct list_head to use as temporary storage * @head: the head for your list. */ #define list_for_each_safe(pos, n, head) \ for (pos = (head)->next, n = pos->next; pos != (head); \ pos = n, n = pos->next) /** * list_for_each_prev - iterate over a list in reverse order * @pos: the &struct list_head to use as a loop counter. * @head: the head for your list. */ #define list_for_each_prev(pos, head) \ for (pos = (head)->prev; pos != (head); pos = pos->prev) #endif /* _LIST_H_ */ fbi-2.10/sane.c0000644000175000017500000002101112506525033011412 0ustar jmmjmm#include #include #include #include #include #include #include #include "readers.h" #include "viewer.h" #include "sane.h" #include "ida.h" #include #include #include #include #include extern int sane_res; /* ---------------------------------------------------------------------- */ static void build_menu(Widget widget, XtPointer clientdata, XtPointer call_data) { WidgetList children,wlist; Cardinal nchildren; const SANE_Device **list; Widget push; XmString str; char action[256]; int rc,i; /* del old */ XtVaGetValues(widget, XtNchildren,&children, XtNnumChildren,&nchildren, NULL); wlist = malloc(sizeof(Widget*)*nchildren); memcpy(wlist,children,sizeof(Widget*)*nchildren); for (i = 0; i < nchildren; i++) XtDestroyWidget(wlist[i]); free(wlist); /* create new */ if (SANE_STATUS_GOOD != (rc = sane_init(NULL,NULL))) { fprintf(stderr,"sane_init: %s\n",sane_strstatus(rc)); goto done; } sane_get_devices(&list,0); if (NULL == list[0]) goto done; for (i = 0; list[i] != NULL; i++) { if (debug) fprintf(stderr,"sane dev: %s | %s | %s | %s\n", list[i]->name, list[i]->vendor, list[i]->model, list[i]->type); str = XmStringGenerate((char*)list[i]->model, NULL, XmMULTIBYTE_TEXT, NULL); push = XtVaCreateManagedWidget(list[i]->name, xmPushButtonWidgetClass,widget, XmNlabelString,str, NULL); XmStringFree(str); sprintf(action,"Scan(%s)",list[i]->name); XtAddCallback(push,XmNactivateCallback,action_cb,strdup(action)); } done: sane_exit(); } void sane_menu(Widget menu) { Widget submenu; int rc; if (SANE_STATUS_GOOD != (rc = sane_init(NULL,NULL))) { fprintf(stderr,"sane_init: %s\n",sane_strstatus(rc)); goto done; } submenu = XmCreatePulldownMenu(menu,"scanM",NULL,0); XtVaCreateManagedWidget("scan",xmCascadeButtonWidgetClass,menu, XmNsubMenuId,submenu,NULL); XtAddCallback(submenu, XmNmapCallback, build_menu, NULL); done: sane_exit(); } /* ---------------------------------------------------------------------- */ /* load */ #define BUF_LINES 16 /* read bigger chunks to reduce overhead */ struct sane_state { SANE_Handle sane; SANE_Parameters parm; SANE_Byte *buf; int started; }; static void dump_desc(SANE_Handle h, int nr, const SANE_Option_Descriptor *opt) { SANE_Bool b; SANE_Int i,flags; fprintf(stderr,"sane opt: name=%s title=%s type=%d unit=%d cap=%d\n", opt->name, opt->title, opt->type, opt->unit, opt->cap); switch (opt->type) { case SANE_TYPE_BOOL: sane_control_option(h, nr, SANE_ACTION_GET_VALUE, &b, &flags); fprintf(stderr," value=%s [bool]\n",b ? "true" : "false"); break; case SANE_TYPE_INT: sane_control_option(h, nr, SANE_ACTION_GET_VALUE, &i, &flags); fprintf(stderr," value=%d [int]\n",i); break; case SANE_TYPE_FIXED: case SANE_TYPE_STRING: case SANE_TYPE_BUTTON: case SANE_TYPE_GROUP: break; } switch (opt->constraint_type) { case SANE_CONSTRAINT_NONE: break; case SANE_CONSTRAINT_RANGE: fprintf(stderr," range=%d-%d\n", opt->constraint.range->min, opt->constraint.range->max); break; case SANE_CONSTRAINT_WORD_LIST: fprintf(stderr," constraint word_list:"); for (i = 1; i <= opt->constraint.word_list[0]; i++) fprintf(stderr," %d",opt->constraint.word_list[i]); fprintf(stderr,"\n"); break; case SANE_CONSTRAINT_STRING_LIST: fprintf(stderr," constraint string_list:"); for (i = 0; opt->constraint.string_list[i] != NULL; i++) fprintf(stderr," %s",opt->constraint.string_list[i]); fprintf(stderr,"\n"); break; }; } static void* sane_idainit(FILE *fp, char *filename, unsigned int page, struct ida_image_info *info, int thumbnail) { const SANE_Option_Descriptor *opt; SANE_Int flags, count; struct sane_state *h; int rc,i,value,dpi = 0; h = malloc(sizeof(*h)); memset(h,0,sizeof(*h)); if (SANE_STATUS_GOOD != (rc = sane_init(NULL,NULL))) { fprintf(stderr,"sane_init: %s\n",sane_strstatus(rc)); goto oops; } if (SANE_STATUS_GOOD != (rc = sane_open(filename,&h->sane))) { fprintf(stderr,"sane_open: %s\n",sane_strstatus(rc)); goto oops; } /* set options */ opt = sane_get_option_descriptor(h->sane,0); rc = sane_control_option(h->sane, 0, SANE_ACTION_GET_VALUE, &count, &flags); for (i = 1; i < count; i++) { opt = sane_get_option_descriptor(h->sane,i); if (opt->name && 0 == strcmp(opt->name,SANE_NAME_SCAN_TL_X)) { value = opt->constraint.range->min; sane_control_option(h->sane, i, SANE_ACTION_SET_VALUE, &value, &flags); } else if (opt->name && 0 == strcmp(opt->name,SANE_NAME_SCAN_TL_Y)) { value = opt->constraint.range->min; sane_control_option(h->sane, i, SANE_ACTION_SET_VALUE, &value, &flags); } else if (opt->name && 0 == strcmp(opt->name,SANE_NAME_SCAN_BR_X)) { value = opt->constraint.range->max; sane_control_option(h->sane, i, SANE_ACTION_SET_VALUE, &value, &flags); } else if (opt->name && 0 == strcmp(opt->name,SANE_NAME_SCAN_BR_Y)) { value = opt->constraint.range->max; sane_control_option(h->sane, i, SANE_ACTION_SET_VALUE, &value, &flags); } else if (opt->name && 0 == strcmp(opt->name,SANE_NAME_PREVIEW)) { value = SANE_FALSE; sane_control_option(h->sane, i, SANE_ACTION_SET_VALUE, &value, &flags); } else if (opt->cap & SANE_CAP_AUTOMATIC) sane_control_option(h->sane, i, SANE_ACTION_SET_AUTO, NULL, &flags); if (opt->name && 0 == strcmp(opt->name,SANE_NAME_SCAN_RESOLUTION)) { if (sane_res) { dpi = sane_res; sane_control_option(h->sane, i, SANE_ACTION_SET_VALUE, &dpi, &flags); } sane_control_option(h->sane, i, SANE_ACTION_GET_VALUE, &dpi, &flags); } if (debug) dump_desc(h->sane,i,opt); } if (SANE_STATUS_GOOD != (rc = sane_start(h->sane))) { fprintf(stderr,"sane_start: %s\n",sane_strstatus(rc)); goto oops; } h->started = 1; if (SANE_STATUS_GOOD != (rc = sane_get_parameters(h->sane,&h->parm))) { fprintf(stderr,"sane_get_parameters: %s\n",sane_strstatus(rc)); goto oops; } if (h->parm.format != SANE_FRAME_GRAY && h->parm.format != SANE_FRAME_RGB) { fprintf(stderr,"sane: unsupported frame format (%d)\n",h->parm.format); goto oops; } if (h->parm.depth != 8) { fprintf(stderr,"sane: unsupported color depth (%d)\n",h->parm.depth); goto oops; } if (-1 == h->parm.lines) { fprintf(stderr,"sane: can't handle unknown image size\n"); goto oops; } info->width = h->parm.pixels_per_line; info->height = h->parm.lines; if (dpi) info->dpi = dpi; h->buf = malloc(h->parm.bytes_per_line * BUF_LINES); if (debug) fprintf(stderr,"sane: scanning %ux%u %s\n",info->width,info->height, (h->parm.format == SANE_FRAME_GRAY) ? "gray" : "color"); return h; oops: if (h->buf) free(h->buf); if (h->started) sane_cancel(h->sane); if (h->sane) sane_close(h->sane); sane_exit(); free(h); return NULL; } static void sane_idaread(unsigned char *dst, unsigned int line, void *data) { struct sane_state *h = data; unsigned int lines, total, offset, len; int rc, i; SANE_Byte *row; if (0 == (line % BUF_LINES)) { lines = BUF_LINES; if (lines > h->parm.lines - line) lines = h->parm.lines - line; total = h->parm.bytes_per_line * lines; offset = 0; while (offset < total) { rc = sane_read(h->sane, h->buf + offset, total - offset, &len); if (rc != SANE_STATUS_GOOD) return; offset += len; } } row = h->buf + (line % BUF_LINES) * h->parm.bytes_per_line; switch (h->parm.format) { case SANE_FRAME_GRAY: for (i = 0; i < h->parm.pixels_per_line; i++) { dst[3*i+0] = row[i]; dst[3*i+1] = row[i]; dst[3*i+2] = row[i]; } break; case SANE_FRAME_RGB: memcpy(dst,row,h->parm.pixels_per_line*3); break; default: fprintf(stderr,"sane: read: internal error\n"); exit(1); } } static void sane_idadone(void *data) { struct sane_state *h = data; sane_cancel(h->sane); sane_close(h->sane); sane_exit(); free(h->buf); free(h); } struct ida_loader sane_loader = { name: "sane interface", init: sane_idainit, read: sane_idaread, done: sane_idadone, }; static void __init init_rd(void) { load_register(&sane_loader); } fbi-2.10/config.h0000644000175000017500000000000012506525033011731 0ustar jmmjmmfbi-2.10/TODO0000644000175000017500000000146512506525033011023 0ustar jmmjmm - some effect filters - improve cut+paste [does complete images only right now ... ] - make the file browser save the thumbnails somewhere (optionally), so it can be much faster the second time ... - screenshots - put images on root window / some batch processing. List is ordered according to my personal priorities. More ideas welcome, but it doesn't automatically mean they will be added to the list. iv is a interactive, small + fast[1] utility and will only support commonly needed features (focus on photos), compareable to xv. If you need a full featured image processing tool with all bells and whistles, better use the gimp. To to stuff batched in scripts, use ImageMagick (convert utility / perl interface). [1] It has finished loading the image while the gimp still shows the splash screen :-) fbi-2.10/RegEdit.c0000644000175000017500000013544112506525033012024 0ustar jmmjmm/* $XConsortium: RegEdit.c /main/5 1995/07/15 20:44:04 drk $ */ /* * Motif * * Copyright (c) 1987-2012, The Open Group. All rights reserved. * * These libraries and programs are free software; you can * redistribute them and/or modify them under the terms of the GNU * Lesser General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * These libraries and programs are distributed in the hope that * they will be useful, but WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public * License along with these librararies and programs; if not, write * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth * Floor, Boston, MA 02110-1301 USA * */ /* * HISTORY */ #include #include #include #include #include "RegEdit.h" #include "RegEditI.h" /* static forward. move from global in the original Editres code */ static void _XEditResCheckMessages(); static void _XEditResPutString8(); static void _XEditResPut8(); static void _XEditResPut16(); static void _XEditResPut32(); static void _XEditResPutWidgetInfo(); static void _XEditResResetStream(); static Boolean _XEditResGet8(); static Boolean _XEditResGet16(); static Boolean _XEditResGetSigned16(); static Boolean _XEditResGet32(); static Boolean _XEditResGetString8(); static Boolean _XEditResGetWidgetInfo(); /* the only entry point here */ void XmdRegisterEditres(Widget toplevel) { XtAddEventHandler(toplevel, (EventMask) 0, TRUE, _XEditResCheckMessages, NULL); } /************************************************************ * * Dump the content of the R5 lib/Xmu/EditresCom.c module. * just move global as static. * ************************************************************/ #define _XEditResPutBool _XEditResPut8 #define _XEditResPutResourceType _XEditResPut8 /************************************************************ * * Local structure definitions. * ************************************************************/ typedef enum { BlockNone, BlockSetValues, BlockAll } EditresBlock; typedef struct _SetValuesEvent { EditresCommand type; /* first field must be type. */ WidgetInfo * widgets; unsigned short num_entries; /* number of set values requests. */ char * name; char * res_type; XtPointer value; unsigned short value_len; } SetValuesEvent; typedef struct _SVErrorInfo { SetValuesEvent * event; ProtocolStream * stream; unsigned short * count; WidgetInfo * entry; } SVErrorInfo; typedef struct _FindChildEvent { EditresCommand type; /* first field must be type. */ WidgetInfo * widgets; short x, y; } FindChildEvent; typedef struct _GenericGetEvent { EditresCommand type; /* first field must be type. */ WidgetInfo * widgets; unsigned short num_entries; /* number of set values requests. */ } GenericGetEvent, GetResEvent, GetGeomEvent; /* * Things that are common to all events. */ typedef struct _AnyEvent { EditresCommand type; /* first field must be type. */ WidgetInfo * widgets; } AnyEvent; /* * The event union. */ typedef union _EditresEvent { AnyEvent any_event; SetValuesEvent set_values_event; GetResEvent get_resources_event; GetGeomEvent get_geometry_event; FindChildEvent find_child_event; } EditresEvent; typedef struct _Globals { EditresBlock block; SVErrorInfo error_info; ProtocolStream stream; ProtocolStream * command_stream; /* command stream. */ } Globals; #define CURRENT_PROTOCOL_VERSION 4L #define streq(a,b) (strcmp( (a), (b) ) == 0) static Atom res_editor_command, res_editor_protocol, client_value; static Globals globals; static void SendFailure(), SendCommand(), InsertWidget(), ExecuteCommand(); static void FreeEvent(), ExecuteSetValues(), ExecuteGetGeometry(); static void ExecuteGetResources(); static void GetCommand(); static void LoadResources(); static Boolean IsChild(); static void DumpChildren(); static char *DumpWidgets(), *DoSetValues(), *DoFindChild(); static char *DoGetGeometry(), *DoGetResources(); /************************************************************ * * Resource Editor Communication Code * ************************************************************/ /* Function Name: _XEditResCheckMessages * Description: This callback routine is set on all shell widgets, * and checks to see if a client message event * has come from the resource editor. * Arguments: w - the shell widget. * data - *** UNUSED *** * event - The X Event that triggered this handler. * cont - *** UNUSED ***. * Returns: none. */ /* ARGSUSED */ static void _XEditResCheckMessages(w, data, event, cont) Widget w; XtPointer data; XEvent *event; Boolean *cont; { Time time; ResIdent ident; static Boolean first_time = FALSE; static Atom res_editor, res_comm; Display * dpy; if (event->type == ClientMessage) { XClientMessageEvent * c_event = (XClientMessageEvent *) event; dpy = XtDisplay(w); if (!first_time) { first_time = TRUE; res_editor = XInternAtom(dpy, EDITRES_NAME, False); res_editor_command = XInternAtom(dpy, EDITRES_COMMAND_ATOM, False); res_editor_protocol = XInternAtom(dpy, EDITRES_PROTOCOL_ATOM, False); /* Used in later procedures. */ client_value = XInternAtom(dpy, EDITRES_CLIENT_VALUE, False); LoadResources(w); } if ((c_event->message_type != res_editor) || (c_event->format != EDITRES_SEND_EVENT_FORMAT)) return; time = c_event->data.l[0]; res_comm = c_event->data.l[1]; ident = (ResIdent) c_event->data.l[2]; if (c_event->data.l[3] != CURRENT_PROTOCOL_VERSION) { _XEditResResetStream(&globals.stream); _XEditResPut8(&globals.stream, CURRENT_PROTOCOL_VERSION); SendCommand(w, res_comm, ident, ProtocolMismatch, &globals.stream); return; } XtGetSelectionValue(w, res_comm, res_editor_command, GetCommand, (XtPointer) (long) ident, time); } } /* Function Name: BuildEvent * Description: Takes the info out the protocol stream an constructs * the proper event structure. * Arguments: w - widget to own selection, in case of error. * sel - selection to send error message beck in. * data - the data for the request. * ident - the id number we are looking for. * length - length of request. * Returns: the event, or NULL. */ #define ERROR_MESSAGE ("Client: Improperly formatted protocol request") static EditresEvent * BuildEvent(w, sel, data, ident, length) Widget w; Atom sel; XtPointer data; ResIdent ident; unsigned long length; { EditresEvent * event; ProtocolStream alloc_stream, *stream; unsigned char temp; register unsigned int i; stream = &alloc_stream; /* easier to think of it this way... */ stream->current = stream->top = (unsigned char *) data; stream->size = HEADER_SIZE; /* size of header. */ /* * Retrieve the Header. */ if (length < HEADER_SIZE) { SendFailure(w, sel, ident, Failure, ERROR_MESSAGE); return(NULL); } (void) _XEditResGet8(stream, &temp); if (temp != ident) /* Id's don't match, ignore request. */ return(NULL); event = (EditresEvent *) XtCalloc(sizeof(EditresEvent), 1); (void) _XEditResGet8(stream, &temp); event->any_event.type = (EditresCommand) temp; (void) _XEditResGet32(stream, &(stream->size)); stream->top = stream->current; /* reset stream to top of value.*/ /* * Now retrieve the data segment. */ switch(event->any_event.type) { case SendWidgetTree: break; /* no additional info */ case SetValues: { SetValuesEvent * sv_event = (SetValuesEvent *) event; if ( !(_XEditResGetString8(stream, &(sv_event->name)) && _XEditResGetString8(stream, &(sv_event->res_type)))) { goto done; } /* * Since we need the value length, we have to pull the * value out by hand. */ if (!_XEditResGet16(stream, &(sv_event->value_len))) goto done; sv_event->value = XtMalloc(sizeof(char) * (sv_event->value_len + 1)); for (i = 0; i < sv_event->value_len; i++) { if (!_XEditResGet8(stream, (unsigned char *) sv_event->value + i)) { goto done; } } ((char*)sv_event->value)[i] = '\0'; /* NULL terminate that sucker. */ if (!_XEditResGet16(stream, &(sv_event->num_entries))) goto done; sv_event->widgets = (WidgetInfo *) XtCalloc(sizeof(WidgetInfo), sv_event->num_entries); for (i = 0; i < sv_event->num_entries; i++) { if (!_XEditResGetWidgetInfo(stream, sv_event->widgets + i)) goto done; } } break; case FindChild: { FindChildEvent * find_event = (FindChildEvent *) event; find_event->widgets = (WidgetInfo *) XtCalloc(sizeof(WidgetInfo), 1); if (!(_XEditResGetWidgetInfo(stream, find_event->widgets) && _XEditResGetSigned16(stream, &(find_event->x)) && _XEditResGetSigned16(stream, &(find_event->y)))) { goto done; } } break; case GetGeometry: case GetResources: { GenericGetEvent * get_event = (GenericGetEvent *) event; if (!_XEditResGet16(stream, &(get_event->num_entries))) goto done; get_event->widgets = (WidgetInfo *) XtCalloc(sizeof(WidgetInfo), get_event->num_entries); for (i = 0; i < get_event->num_entries; i++) { if (!_XEditResGetWidgetInfo(stream, get_event->widgets + i)) goto done; } } break; default: { char buf[BUFSIZ]; sprintf(buf, "Unknown Protocol request %d.",event->any_event.type); SendFailure(w, sel, ident, buf); return(NULL); } } return(event); done: SendFailure(w, sel, ident, ERROR_MESSAGE); FreeEvent(event); return(NULL); } /* Function Name: FreeEvent * Description: Frees the event structure and any other pieces * in it that need freeing. * Arguments: event - the event to free. * Returns: none. */ static void FreeEvent(event) EditresEvent * event; { if (event->any_event.widgets != NULL) { XtFree((char *)event->any_event.widgets->ids); XtFree((char *)event->any_event.widgets); } if (event->any_event.type == SetValues) { XtFree(event->set_values_event.name); /* XtFree does not free if */ XtFree(event->set_values_event.res_type); /* value is NULL. */ } XtFree((char *)event); } /* Function Name: GetCommand * Description: Gets the Command out of the selection asserted by the * resource manager. * Arguments: (See Xt XtConvertSelectionProc) * data - contains the ident number for the command. * Returns: none. */ /* ARGSUSED */ static void GetCommand(w, data, selection, type, value, length, format) Widget w; XtPointer data, value; Atom *selection, *type; unsigned long *length; int * format; { ResIdent ident = (ResIdent) (long) data; EditresEvent * event; if ( (*type != res_editor_protocol) || (*format != EDITRES_FORMAT) ) return; if ((event = BuildEvent(w, *selection, value, ident, *length)) != NULL) { ExecuteCommand(w, *selection, ident, event); FreeEvent(event); } } /* Function Name: ExecuteCommand * Description: Executes a command string received from the * resource editor. * Arguments: w - a widget. * command - the command to execute. * value - the associated with the command. * Returns: none. * * NOTES: munges str */ /* ARGSUSED */ static void ExecuteCommand(w, sel, ident, event) Widget w; Atom sel; ResIdent ident; EditresEvent * event; { char * (*func)(); char * str; if (globals.block == BlockAll) { SendFailure(w, sel, ident, "This client has blocked all Editres commands."); return; } else if ((globals.block == BlockSetValues) && (event->any_event.type == SetValues)) { SendFailure(w, sel, ident, "This client has blocked all SetValues requests."); return; } switch(event->any_event.type) { case SendWidgetTree: func = DumpWidgets; break; case SetValues: func = DoSetValues; break; case FindChild: func = DoFindChild; break; case GetGeometry: func = DoGetGeometry; break; case GetResources: func = DoGetResources; break; default: { char buf[BUFSIZ]; sprintf(buf,"Unknown Protocol request %d.",event->any_event.type); SendFailure(w, sel, ident, buf); return; } } _XEditResResetStream(&globals.stream); if ((str = (*func)(w, event, &globals.stream)) == NULL) SendCommand(w, sel, ident, PartialSuccess, &globals.stream); else { SendFailure(w, sel, ident, str); XtFree(str); } } /* Function Name: ConvertReturnCommand * Description: Converts a selection. * Arguments: w - the widget that owns the selection. * selection - selection to convert. * target - target type for this selection. * type_ret - type of the selection. * value_ret - selection value; * length_ret - lenght of this selection. * format_ret - the format the selection is in. * Returns: True if conversion was sucessful. */ /* ARGSUSED */ static Boolean ConvertReturnCommand(w, selection, target, type_ret, value_ret, length_ret, format_ret) Widget w; Atom * selection, * target, * type_ret; XtPointer *value_ret; unsigned long * length_ret; int * format_ret; { /* * I assume the intrinsics give me the correct selection back. */ if ((*target != client_value)) return(FALSE); *type_ret = res_editor_protocol; *value_ret = (XtPointer) globals.command_stream->real_top; *length_ret = globals.command_stream->size + HEADER_SIZE; *format_ret = EDITRES_FORMAT; return(TRUE); } /* Function Name: CommandDone * Description: done with the selection. * Arguments: *** UNUSED *** * Returns: none. */ /* ARGSUSED */ static void CommandDone(widget, selection, target) Widget widget; Atom *selection; Atom *target; { /* Keep the toolkit from automaticaly freeing the selection value */ } /* Function Name: SendFailure * Description: Sends a failure message. * Arguments: w - the widget to own the selection. * sel - the selection to assert. * ident - the identifier. * str - the error message. * Returns: none. */ static void SendFailure(w, sel, ident, str) Widget w; Atom sel; ResIdent ident; char * str; { _XEditResResetStream(&globals.stream); _XEditResPutString8(&globals.stream, str); SendCommand(w, sel, ident, Failure, &globals.stream); } /* Function Name: BuildReturnPacket * Description: Builds a return packet, given the data to send. * Arguments: ident - the identifier. * command - the command code. * stream - the protocol stream. * Returns: packet - the packet to send. */ static XtPointer BuildReturnPacket(ident, command, stream) ResIdent ident; EditresCommand command; ProtocolStream * stream; { long old_alloc, old_size; unsigned char * old_current; /* * We have cleverly keep enough space at the top of the header * for the return protocol stream, so all we have to do is * fill in the space. */ /* * Fool the insert routines into putting the header in the right * place while being damn sure not to realloc (that would be very bad. */ old_current = stream->current; old_alloc = stream->alloc; old_size = stream->size; stream->current = stream->real_top; stream->alloc = stream->size + (2 * HEADER_SIZE); _XEditResPut8(stream, ident); _XEditResPut8(stream, (unsigned char) command); _XEditResPut32(stream, old_size); stream->alloc = old_alloc; stream->current = old_current; stream->size = old_size; return((XtPointer) stream->real_top); } /* Function Name: SendCommand * Description: Builds a return command line. * Arguments: w - the widget to own the selection. * sel - the selection to assert. * ident - the identifier. * command - the command code. * stream - the protocol stream. * Returns: none. */ static void SendCommand(w, sel, ident, command, stream) Widget w; Atom sel; ResIdent ident; EditresCommand command; ProtocolStream * stream; { BuildReturnPacket(ident, command, stream); globals.command_stream = stream; /* * I REALLY want to own the selection. Since this was not triggered * by a user action, and I am the only one using this atom it is safe to * use CurrentTime. */ XtOwnSelection(w, sel, CurrentTime, ConvertReturnCommand, NULL, CommandDone); } /************************************************************ * * Generic Utility Functions. * ************************************************************/ /* Function Name: FindChildren * Description: Retuns all children (popup, normal and otherwise) * of this widget * Arguments: parent - the parent widget. * children - the list of children. * normal - return normal children. * popup - return popup children. * Returns: the number of children. */ static int FindChildren(parent, children, normal, popup) Widget parent, **children; Boolean normal, popup; { CompositeWidget cw = (CompositeWidget) parent; int i, num_children, current = 0; num_children = 0; if (XtIsWidget(parent) && popup) num_children += parent->core.num_popups; if (XtIsComposite(parent) && normal) num_children += cw->composite.num_children; if (num_children == 0) { *children = NULL; return(0); } *children =(Widget*) XtMalloc((Cardinal) sizeof(Widget) * num_children); if (XtIsComposite(parent) && normal) for (i = 0; i < cw->composite.num_children; i++,current++) (*children)[current] = cw->composite.children[i]; if (XtIsWidget(parent) && popup) for ( i = 0; i < parent->core.num_popups; i++, current++) (*children)[current] = parent->core.popup_list[i]; return(num_children); } /* Function Name: IsChild * Description: check to see of child is a child of parent. * Arguments: top - the top of the tree. * parent - the parent widget. * child - the child. * Returns: none. */ static Boolean IsChild(top, parent, child) Widget top, parent, child; { int i, num_children; Widget * children; if (parent == NULL) return(top == child); num_children = FindChildren(parent, &children, TRUE, TRUE); for (i = 0; i < num_children; i++) { if (children[i] == child) { XtFree((char *)children); return(TRUE); } } XtFree((char *)children); return(FALSE); } /* Function Name: VerifyWidget * Description: Makes sure all the widgets still exist. * Arguments: w - any widget in the tree. * info - the info about the widget to verify. * Returns: an error message or NULL. */ static char * VerifyWidget(w, info) Widget w; WidgetInfo *info; { Widget top; register int count; register Widget parent; register unsigned long * child; for (top = w; XtParent(top) != NULL; top = XtParent(top)) {} parent = NULL; child = info->ids; count = 0; while (TRUE) { if (!IsChild(top, parent, (Widget) *child)) return(XtNewString("This widget no longer exists in the client.")); if (++count == info->num_widgets) break; parent = (Widget) *child++; } info->real_widget = (Widget) *child; return(NULL); } /************************************************************ * * Code to Perform SetValues operations. * ************************************************************/ /* Function Name: DoSetValues * Description: performs the setvalues requested. * Arguments: w - a widget in the tree. * event - the event that caused this action. * stream - the protocol stream to add. * Returns: NULL. */ static char * DoSetValues(w, event, stream) Widget w; EditresEvent * event; ProtocolStream * stream; { char * str; register unsigned i; unsigned short count = 0; SetValuesEvent * sv_event = (SetValuesEvent *) event; _XEditResPut16(stream, count); /* insert 0, will be overwritten later. */ for (i = 0 ; i < sv_event->num_entries; i++) { if ((str = VerifyWidget(w, &(sv_event->widgets[i]))) != NULL) { _XEditResPutWidgetInfo(stream, &(sv_event->widgets[i])); _XEditResPutString8(stream, str); XtFree(str); count++; } else ExecuteSetValues(sv_event->widgets[i].real_widget, sv_event, sv_event->widgets + i, stream, &count); } /* * Overwrite the first 2 bytes with the real count. */ *(stream->top) = count >> XER_NBBY; *(stream->top + 1) = count; return(NULL); } /* Function Name: HandleToolkitErrors * Description: Handles X Toolkit Errors. * Arguments: name - name of the error. * type - type of the error. * class - class of the error. * msg - the default message. * params, num_params - the extra parameters for this message. * Returns: none. */ /* ARGSUSED */ static void HandleToolkitErrors(name, type, class, msg, params, num_params) String name, type, class, msg, *params; Cardinal * num_params; { SVErrorInfo * info = &globals.error_info; char buf[BUFSIZ]; if ( streq(name, "unknownType") ) sprintf(buf, "The `%s' resource is not used by this widget.", info->event->name); else if ( streq(name, "noColormap") ) sprintf(buf, msg, params[0]); else if (streq(name, "conversionFailed") || streq(name, "conversionError")) { if (streq(info->event->value, XtRString)) sprintf(buf, "Could not convert the string '%s' for the `%s' resource.", (char*)info->event->value, info->event->name); else sprintf(buf, "Could not convert the `%s' resource.", info->event->name); } else sprintf(buf, "Name: %s, Type: %s, Class: %s, Msg: %s", name, type, class, msg); /* * Insert this info into the protocol stream, and update the count. */ (*(info->count))++; _XEditResPutWidgetInfo(info->stream, info->entry); _XEditResPutString8(info->stream, buf); } /* Function Name: ExecuteSetValues * Description: Performs a setvalues for a given command. * Arguments: w - the widget to perform the set_values on. * sv_event - the set values event. * sv_info - the set_value info. * Returns: none. */ static void ExecuteSetValues(w, sv_event, entry, stream, count) Widget w; SetValuesEvent * sv_event; WidgetInfo * entry; ProtocolStream * stream; unsigned short * count; { XtErrorMsgHandler old; SVErrorInfo * info = &globals.error_info; info->event = sv_event; /* No data can be passed to */ info->stream = stream; /* an error handler, so we */ info->count = count; /* have to use a global, YUCK... */ info->entry = entry; old = XtAppSetWarningMsgHandler(XtWidgetToApplicationContext(w), HandleToolkitErrors); XtVaSetValues(w, XtVaTypedArg, sv_event->name, sv_event->res_type, sv_event->value, sv_event->value_len, NULL); (void)XtAppSetWarningMsgHandler(XtWidgetToApplicationContext(w), old); } /************************************************************ * * Code for Creating and dumping widget tree. * ************************************************************/ /* Function Name: DumpWidgets * Description: Given a widget it builds a protocol packet * containing the entire widget heirarchy. * Arguments: w - a widget in the tree. * event - the event that caused this action. * stream - the protocol stream to add. * Returns: NULL */ /* ARGSUSED */ static char * DumpWidgets(w, event, stream) Widget w; EditresEvent * event; /* UNUSED */ ProtocolStream * stream; { unsigned short count = 0; /* Find Tree's root. */ for ( ; XtParent(w) != NULL; w = XtParent(w)) {} /* * hold space for count, overwritten later. */ _XEditResPut16(stream, (unsigned int) 0); DumpChildren(w, stream, &count); /* * Overwrite the first 2 bytes with the real count. */ *(stream->top) = count >> XER_NBBY; *(stream->top + 1) = count; return(NULL); } /* Function Name: DumpChildren * Description: Adds a child's name to the list. * Arguments: w - the widget to dump. * stream - the stream to dump to. * count - number of dumps we have performed. * Returns: none. */ /* This is a trick/kludge. To make shared libraries happier (linking * against Xmu but not linking against Xt, and apparently even work * as we desire on SVR4, we need to avoid an explicit data reference * to applicationShellWidgetClass. XtIsTopLevelShell is known * (implementation dependent assumption!) to use a bit flag. So we * go that far. Then, we test whether it is an applicationShellWidget * class by looking for an explicit class name. Seems pretty safe. */ static Bool isApplicationShell(w) Widget w; { register WidgetClass c; if (!XtIsTopLevelShell(w)) return False; for (c = XtClass(w); c; c = c->core_class.superclass) { if (!strcmp(c->core_class.class_name, "ApplicationShell")) return True; } return False; } static void DumpChildren(w, stream, count) Widget w; ProtocolStream * stream; unsigned short *count; { int i, num_children; Widget *children; unsigned long window; char * class; (*count)++; InsertWidget(stream, w); /* Insert the widget into the stream. */ _XEditResPutString8(stream, XtName(w)); /* Insert name */ if (isApplicationShell(w)) class = ((ApplicationShellWidget) w)->application.class; else class = XtClass(w)->core_class.class_name; _XEditResPutString8(stream, class); /* Insert class */ if (XtIsWidget(w)) if (XtIsRealized(w)) window = XtWindow(w); else window = EDITRES_IS_UNREALIZED; else window = EDITRES_IS_OBJECT; _XEditResPut32(stream, window); /* Insert window id. */ /* * Find children and recurse. */ num_children = FindChildren(w, &children, TRUE, TRUE); for (i = 0; i < num_children; i++) DumpChildren(children[i], stream, count); XtFree((char *)children); } /************************************************************ * * Code for getting the geometry of widgets. * ************************************************************/ /* Function Name: DoGetGeometry * Description: retrieves the Geometry of each specified widget. * Arguments: w - a widget in the tree. * event - the event that caused this action. * stream - the protocol stream to add. * Returns: NULL */ static char * DoGetGeometry(w, event, stream) Widget w; EditresEvent * event; ProtocolStream * stream; { unsigned i; char * str; GetGeomEvent * geom_event = (GetGeomEvent *) event; _XEditResPut16(stream, geom_event->num_entries); for (i = 0 ; i < geom_event->num_entries; i++) { /* * Send out the widget id. */ _XEditResPutWidgetInfo(stream, &(geom_event->widgets[i])); if ((str = VerifyWidget(w, &(geom_event->widgets[i]))) != NULL) { _XEditResPutBool(stream, True); /* an error occured. */ _XEditResPutString8(stream, str); /* set message. */ XtFree(str); } else ExecuteGetGeometry(geom_event->widgets[i].real_widget, stream); } return(NULL); } /* Function Name: ExecuteGetGeometry * Description: Gets the geometry for each widget specified. * Arguments: w - the widget to get geom on. * stream - stream to append to. * Returns: True if no error occured. */ static void ExecuteGetGeometry(w, stream) Widget w; ProtocolStream * stream; { int i; Boolean mapped_when_man; Dimension width, height, border_width; Arg args[8]; Cardinal num_args = 0; Position x, y; if ( !XtIsRectObj(w) || (XtIsWidget(w) && !XtIsRealized(w)) ) { _XEditResPutBool(stream, False); /* no error. */ _XEditResPutBool(stream, False); /* not visable. */ for (i = 0; i < 5; i++) /* fill in extra space with 0's. */ _XEditResPut16(stream, 0); return; } XtSetArg(args[num_args], XtNwidth, &width); num_args++; XtSetArg(args[num_args], XtNheight, &height); num_args++; XtSetArg(args[num_args], XtNborderWidth, &border_width); num_args++; XtSetArg(args[num_args], XtNmappedWhenManaged, &mapped_when_man); num_args++; XtGetValues(w, args, num_args); if (!(XtIsManaged(w) && mapped_when_man) && XtIsWidget(w)) { XWindowAttributes attrs; /* * The toolkit does not maintain mapping state, we have * to go to the server. */ if (XGetWindowAttributes(XtDisplay(w), XtWindow(w), &attrs) != 0) { if (attrs.map_state != IsViewable) { _XEditResPutBool(stream, False); /* no error. */ _XEditResPutBool(stream, False); /* not visable. */ for (i = 0; i < 5; i++) /* fill in extra space with 0's. */ _XEditResPut16(stream, 0); return; } } else { _XEditResPut8(stream, True); /* Error occured. */ _XEditResPutString8(stream, "XGetWindowAttributes failed."); return; } } XtTranslateCoords(w, -((int) border_width), -((int) border_width), &x, &y); _XEditResPutBool(stream, False); /* no error. */ _XEditResPutBool(stream, True); /* Visable. */ _XEditResPut16(stream, x); _XEditResPut16(stream, y); _XEditResPut16(stream, width); _XEditResPut16(stream, height); _XEditResPut16(stream, border_width); } /************************************************************ * * Code for executing FindChild. * ************************************************************/ /* Function Name: PositionInChild * Description: returns true if this location is in the child. * Arguments: child - the child widget to check. * x, y - location of point to check in the parent's * coord space. * Returns: TRUE if the position is in this child. */ static Boolean PositionInChild(child, x, y) Widget child; int x, y; { Arg args[6]; Cardinal num; Dimension width, height, border_width; Position child_x, child_y; Boolean mapped_when_managed; if (!XtIsRectObj(child)) /* we must at least be a rect obj. */ return(FALSE); num = 0; XtSetArg(args[num], XtNmappedWhenManaged, &mapped_when_managed); num++; XtSetArg(args[num], XtNwidth, &width); num++; XtSetArg(args[num], XtNheight, &height); num++; XtSetArg(args[num], XtNx, &child_x); num++; XtSetArg(args[num], XtNy, &child_y); num++; XtSetArg(args[num], XtNborderWidth, &border_width); num++; XtGetValues(child, args, num); /* * The only way we will know of the widget is mapped is to see if * mapped when managed is True and this is a managed child. Otherwise * we will have to ask the server if this window is mapped. */ if (XtIsWidget(child) && !(mapped_when_managed && XtIsManaged(child)) ) { XWindowAttributes attrs; if (XGetWindowAttributes(XtDisplay(child), XtWindow(child), &attrs) != 0) { /* oops */ } else if (attrs.map_state != IsViewable) return(FALSE); } return (x >= child_x) && (x <= (child_x + (Position)width + 2 * (Position)border_width)) && (y >= child_y) && (y <= (child_y + (Position)height + 2 * (Position)border_width)); } /* Function Name: _FindChild * Description: Finds the child that actually contatians the point shown. * Arguments: parent - a widget that is known to contain the point * specified. * x, y - The point in coordinates relative to the * widget specified. * Returns: none. */ static Widget _FindChild(parent, x, y) Widget parent; int x, y; { Widget * children; int i = FindChildren(parent, &children, TRUE, FALSE); while (i > 0) { i--; if (PositionInChild(children[i], x, y)) { Widget child = children[i]; XtFree((char *)children); return(_FindChild(child, x - child->core.x, y - child->core.y)); } } XtFree((char *)children); return(parent); } /* Function Name: DoFindChild * Description: finds the child that contains the location specified. * Arguments: w - a widget in the tree. * event - the event that caused this action. * stream - the protocol stream to add. * Returns: an allocated error message if something went horribly * wrong and no set values were performed, else NULL. */ static char * DoFindChild(w, event, stream) Widget w; EditresEvent * event; ProtocolStream * stream; { char * str; Widget parent, child; Position parent_x, parent_y; FindChildEvent * find_event = (FindChildEvent *) event; if ((str = VerifyWidget(w, find_event->widgets)) != NULL) return(str); parent = find_event->widgets->real_widget; XtTranslateCoords(parent, (Position) 0, (Position) 0, &parent_x, &parent_y); child = _FindChild(parent, find_event->x - (int) parent_x, find_event->y - (int) parent_y); InsertWidget(stream, child); return(NULL); } /************************************************************ * * Procedures for performing GetResources. * ************************************************************/ /* Function Name: DoGetResources * Description: Gets the Resources associated with the widgets passed. * Arguments: w - a widget in the tree. * event - the event that caused this action. * stream - the protocol stream to add. * Returns: NULL */ static char * DoGetResources(w, event, stream) Widget w; EditresEvent * event; ProtocolStream * stream; { unsigned int i; char * str; GetResEvent * res_event = (GetResEvent *) event; _XEditResPut16(stream, res_event->num_entries); /* number of replys */ for (i = 0 ; i < res_event->num_entries; i++) { /* * Send out the widget id. */ _XEditResPutWidgetInfo(stream, &(res_event->widgets[i])); if ((str = VerifyWidget(w, &(res_event->widgets[i]))) != NULL) { _XEditResPutBool(stream, True); /* an error occured. */ _XEditResPutString8(stream, str); /* set message. */ XtFree(str); } else { _XEditResPutBool(stream, False); /* no error occured. */ ExecuteGetResources(res_event->widgets[i].real_widget, stream); } } return(NULL); } /* Function Name: ExecuteGetResources. * Description: Gets the resources for any individual widget. * Arguments: w - the widget to get resources on. * stream - the protocol stream. * Returns: none. */ static void ExecuteGetResources(w, stream) Widget w; ProtocolStream * stream; { XtResourceList norm_list, cons_list; Cardinal num_norm, num_cons; register int i; /* * Get Normal Resources. */ XtGetResourceList(XtClass(w), &norm_list, &num_norm); if (XtParent(w) != NULL) XtGetConstraintResourceList(XtClass(XtParent(w)),&cons_list,&num_cons); else num_cons = 0; _XEditResPut16(stream, num_norm + num_cons); /* how many resources. */ /* * Insert all the normal resources. */ for ( i = 0; i < (int) num_norm; i++) { _XEditResPutResourceType(stream, NormalResource); _XEditResPutString8(stream, norm_list[i].resource_name); _XEditResPutString8(stream, norm_list[i].resource_class); _XEditResPutString8(stream, norm_list[i].resource_type); } XtFree((char *) norm_list); /* * Insert all the constraint resources. */ if (num_cons > 0) { for ( i = 0; i < (int) num_cons; i++) { _XEditResPutResourceType(stream, ConstraintResource); _XEditResPutString8(stream, cons_list[i].resource_name); _XEditResPutString8(stream, cons_list[i].resource_class); _XEditResPutString8(stream, cons_list[i].resource_type); } XtFree((char *) cons_list); } } /************************************************************ * * Code for inserting values into the protocol stream. * ************************************************************/ /* Function Name: InsertWidget * Description: Inserts the full parent heirarchy of this * widget into the protocol stream as a widget list. * Arguments: stream - the protocol stream. * w - the widget to insert. * Returns: none */ static void InsertWidget(stream, w) ProtocolStream * stream; Widget w; { Widget temp; unsigned long * widget_list; register int i, num_widgets; for (temp = w, i = 0; temp != 0; temp = XtParent(temp), i++) {} num_widgets = i; widget_list = (unsigned long *) XtMalloc(sizeof(unsigned long) * num_widgets); /* * Put the widgets into the list. * make sure that they are inserted in the list from parent -> child. */ for (i--, temp = w; temp != NULL; temp = XtParent(temp), i--) widget_list[i] = (unsigned long) temp; _XEditResPut16(stream, num_widgets); /* insert number of widgets. */ for (i = 0; i < num_widgets; i++) /* insert Widgets themselves. */ _XEditResPut32(stream, widget_list[i]); XtFree((char *)widget_list); } /************************************************************ * * All of the following routines are public. * ************************************************************/ /* Function Name: _XEditResPutString8 * Description: Inserts a string into the protocol stream. * Arguments: stream - stream to insert string into. * str - string to insert. * Returns: none. */ static void _XEditResPutString8(stream, str) ProtocolStream * stream; char * str; { int i, len = strlen(str); _XEditResPut16(stream, len); for (i = 0 ; i < len ; i++, str++) _XEditResPut8(stream, *str); } /* Function Name: _XEditResPut8 * Description: Inserts an 8 bit integer into the protocol stream. * Arguments: stream - stream to insert string into. * value - value to insert. * Returns: none */ static void _XEditResPut8(stream, value) ProtocolStream * stream; unsigned int value; { unsigned char temp; if (stream->size >= stream->alloc) { stream->alloc += 100; stream->real_top = (unsigned char *) XtRealloc( (char *)stream->real_top, stream->alloc + HEADER_SIZE); stream->top = stream->real_top + HEADER_SIZE; stream->current = stream->top + stream->size; } temp = (unsigned char) (value & BYTE_MASK); *((stream->current)++) = temp; (stream->size)++; } /* Function Name: _XEditResPut16 * Description: Inserts a 16 bit integer into the protocol stream. * Arguments: stream - stream to insert string into. * value - value to insert. * Returns: void */ static void _XEditResPut16(stream, value) ProtocolStream * stream; unsigned int value; { _XEditResPut8(stream, (value >> XER_NBBY) & BYTE_MASK); _XEditResPut8(stream, value & BYTE_MASK); } /* Function Name: _XEditResPut32 * Description: Inserts a 32 bit integer into the protocol stream. * Arguments: stream - stream to insert string into. * value - value to insert. * Returns: void */ static void _XEditResPut32(stream, value) ProtocolStream * stream; unsigned long value; { int i; for (i = 3; i >= 0; i--) _XEditResPut8(stream, (value >> (XER_NBBY*i)) & BYTE_MASK); } /* Function Name: _XEditResPutWidgetInfo * Description: Inserts the widget info into the protocol stream. * Arguments: stream - stream to insert widget info into. * info - info to insert. * Returns: none */ static void _XEditResPutWidgetInfo(stream, info) ProtocolStream * stream; WidgetInfo * info; { unsigned int i; _XEditResPut16(stream, info->num_widgets); for (i = 0; i < info->num_widgets; i++) _XEditResPut32(stream, info->ids[i]); } /************************************************************ * * Code for retrieving values from the protocol stream. * ************************************************************/ /* Function Name: _XEditResResetStream * Description: resets the protocol stream * Arguments: stream - the stream to reset. * Returns: none. */ static void _XEditResResetStream(stream) ProtocolStream * stream; { stream->current = stream->top; stream->size = 0; if (stream->real_top == NULL) { stream->real_top = (unsigned char *) XtRealloc( (char *)stream->real_top, stream->alloc + HEADER_SIZE); stream->top = stream->real_top + HEADER_SIZE; stream->current = stream->top + stream->size; } } /* * NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE * * The only modified field if the "current" field. * * The only fields that must be set correctly are the "current", "top" * and "size" fields. */ /* Function Name: _XEditResGetg8 * Description: Retrieves an unsigned 8 bit value * from the protocol stream. * Arguments: stream. * val - a pointer to value to return. * Returns: TRUE if sucessful. */ static Boolean _XEditResGet8(stream, val) ProtocolStream * stream; unsigned char * val; { if (stream->size < (stream->current - stream->top)) return(FALSE); *val = *((stream->current)++); return(TRUE); } /* Function Name: _XEditResGet16 * Description: Retrieves an unsigned 16 bit value * from the protocol stream. * Arguments: stream. * val - a pointer to value to return. * Returns: TRUE if sucessful. */ static Boolean _XEditResGet16(stream, val) ProtocolStream * stream; unsigned short * val; { unsigned char temp1, temp2; if ( !(_XEditResGet8(stream, &temp1) && _XEditResGet8(stream, &temp2)) ) return(FALSE); *val = (((unsigned short) temp1 << XER_NBBY) + ((unsigned short) temp2)); return(TRUE); } /* Function Name: _XEditResGetSigned16 * Description: Retrieves an signed 16 bit value from the protocol stream. * Arguments: stream. * val - a pointer to value to return. * Returns: TRUE if sucessful. */ static Boolean _XEditResGetSigned16(stream, val) ProtocolStream * stream; short * val; { unsigned char temp1, temp2; if ( !(_XEditResGet8(stream, &temp1) && _XEditResGet8(stream, &temp2)) ) return(FALSE); if (temp1 & (1 << (XER_NBBY - 1))) { /* If the sign bit is active. */ *val = -1; /* store all 1's */ *val &= (temp1 << XER_NBBY); /* Now and in the MSB */ *val &= temp2; /* and LSB */ } else *val = (((unsigned short) temp1 << XER_NBBY) + ((unsigned short) temp2)); return(TRUE); } /* Function Name: _XEditResGet32 * Description: Retrieves an unsigned 32 bit value * from the protocol stream. * Arguments: stream. * val - a pointer to value to return. * Returns: TRUE if sucessful. */ static Boolean _XEditResGet32(stream, val) ProtocolStream * stream; unsigned long * val; { unsigned short temp1, temp2; if ( !(_XEditResGet16(stream, &temp1) && _XEditResGet16(stream, &temp2)) ) return(FALSE); *val = (((unsigned short) temp1 << (XER_NBBY * 2)) + ((unsigned short) temp2)); return(TRUE); } /* Function Name: _XEditResGetString8 * Description: Retrieves an 8 bit string value from the protocol stream. * Arguments: stream - the protocol stream * str - the string to retrieve. * Returns: True if retrieval was successful. */ static Boolean _XEditResGetString8(stream, str) ProtocolStream * stream; char ** str; { unsigned short len; register unsigned i; if (!_XEditResGet16(stream, &len)) { return(FALSE); } *str = XtMalloc(sizeof(char) * (len + 1)); for (i = 0; i < len; i++) { if (!_XEditResGet8(stream, (unsigned char *) *str + i)) { XtFree(*str); *str = NULL; return(FALSE); } } (*str)[i] = '\0'; /* NULL terminate that sucker. */ return(TRUE); } /* Function Name: _XEditResGetWidgetInfo * Description: Retrieves the list of widgets that follow and stores * them in the widget info structure provided. * Arguments: stream - the protocol stream * info - the widget info struct to store into. * Returns: True if retrieval was successful. */ static Boolean _XEditResGetWidgetInfo(stream, info) ProtocolStream * stream; WidgetInfo * info; { unsigned int i; if (!_XEditResGet16(stream, &(info->num_widgets))) return(FALSE); info->ids = (unsigned long *) XtMalloc(sizeof(long) * (info->num_widgets)); for (i = 0; i < info->num_widgets; i++) { if (!_XEditResGet32(stream, info->ids + i)) { XtFree((char *)info->ids); info->ids = NULL; return(FALSE); } } return(TRUE); } /************************************************************ * * Code for Loading the EditresBlock resource. * ************************************************************/ /* Function Name: CvStringToBlock * Description: Converts a string to an editres block value. * Arguments: dpy - the display. * args, num_args - **UNUSED ** * from_val, to_val - value to convert, and where to put result * converter_data - ** UNUSED ** * Returns: TRUE if conversion was sucessful. */ /* ARGSUSED */ static Boolean CvtStringToBlock(dpy, args, num_args, from_val, to_val, converter_data) Display * dpy; XrmValue * args; Cardinal * num_args; XrmValue * from_val, * to_val; XtPointer * converter_data; { char ptr[BUFSIZ]; static EditresBlock block; /* XmuCopyISOLatin1Lowered(ptr, from_val->addr);*/ if (streq(ptr, "none")) block = BlockNone; else if (streq(ptr, "setvalues")) block = BlockSetValues; else if (streq(ptr, "all")) block = BlockAll; else { Cardinal num_params = 1; String params[1]; params[0] = from_val->addr; XtAppWarningMsg(XtDisplayToApplicationContext(dpy), "CvtStringToBlock", "unknownValue", "EditresError", "Could not convert string \"%s\" to EditresBlock.", params, &num_params); return(FALSE); } if (to_val->addr != NULL) { if (to_val->size < sizeof(EditresBlock)) { to_val->size = sizeof(EditresBlock); return(FALSE); } *(EditresBlock *)(to_val->addr) = block; } else to_val->addr = (XtPointer) block; to_val->size = sizeof(EditresBlock); return(TRUE); } #define XtREditresBlock ("EditresBlock") /* Function Name: LoadResources * Description: Loads a global resource the determines of this * application should allow Editres requests. * Arguments: w - any widget in the tree. * Returns: none. */ static void LoadResources(w) Widget w; { static XtResource resources[] = { {"editresBlock", "EditresBlock", XtREditresBlock, sizeof(EditresBlock), XtOffsetOf(Globals, block), XtRImmediate, (XtPointer) BlockNone} }; for (; XtParent(w) != NULL; w = XtParent(w)) {} XtAppSetTypeConverter(XtWidgetToApplicationContext(w), XtRString, XtREditresBlock, CvtStringToBlock, NULL, (Cardinal) 0, XtCacheAll, NULL); XtGetApplicationResources( w, (caddr_t) &globals, resources, XtNumber(resources), NULL, (Cardinal) 0); } fbi-2.10/ida.man.fr0000644000175000017500000001136412506525033012172 0ustar jmmjmm.TH IDA 1 "(c) 2001-2012 Gerd Hoffmann" "IDA 2.09" "Programme de visualisation et de modification d'image" \# \# .SH NOM ida - programme de visualisation et de modification d'image \# \# .SH SYNOPSIS \fBida\fP [\fIoptions\fP] \fIfichier …\fP \# \# .SH DESCRIPTION .BR Ida est une application petit et rapide pour visualiser des images. Quelques fonctions rudimentaires d'édition sont aussi disponibles. .P Vous pouvez spécifier un nombre quelconque de fichiers image en argument sur la ligne de commande. Ou vous pouvez lire un unique fichier image depuis l'entrée standard en spécifiant "-" comme seul argument ("\fIxwd | ida -\fP" fonctionne bien pour les copies d'écran). \# \# .SH OPTIONS .BR Ida comprend les options habituelles (-geometry et autres). Les options supplémentaires sont : .TP .B -help Afficher un court message d'aide. .TP .BI "-pcd" "\ n" Définir la taille pour les images PhotoCD (\fIn = 1 .. 5\fP, par défaut 3). .TP .B -debug Activer les messages d'erreur. Avec pour effet indésirable d'afficher les messages d'erreur seulement sur la sortie d'erreur standard et \fBnon\fP dans une boîte de dialogue. \# \# .SH "POUR DÉMARRER" .SS Fonctions de la souris .P Avec le bouton gauche de la souris vous pouvez créer et modifier un rectangle de sélection Le bouton du milieu est utilisé pour démarrer les opérations de glisser-déposer. Le bouton droit fait apparaître la fenêtre de contrôle avec les menus, la barre d'outils et la liste de fichier. .SS Racourcis clavier .P De nombreux racourcis clavier utilisés par .BR xv sont aussi disponibles dans .BR "ida" "." Si vous êtes familier avec .BR xv il devrait être facile pour vous de démarrer avec .BR "ida" "." .P Tous les racourcis clavier disponibles sont aussi listés dans les menus de la fanêtre de contrôle. Les plus importants sont listés ci-dessous : .TP \fBESPACE\fP Fichier suivant. .TP \fBRETOUR_ARRIÈRE\fP Fichier précédent. .TP \fBFLÉCHE_GAUCHE\fP, \fBFLÉCHE_DROITE\fP, \fBFLÉCHE_HAUT\fP, \fBFLÉCHE_BAS\fP Défilement (maintenir enfoncée la touche \fBCtrl\fP pour un grand pas). .TP \fB+/-\fP Zoomer en avant / arrière. .TP \fBq\fP Quitter. .SS Formats d'image pris en charge .TP .B Lecture: \fIBMP\fP (sans compression), \fIPhotoCD\fP, \fIPPM\fP, \fIXBM\fP, \fIXPM\fP, \fIXWD\fP, \fIGIF\fP, \fIJPEG\fP, \fIPNG\fP, \fITIFF\fP. Les quatre derniers sont pris en charge en utilisant les bibliothèques courantes, c-à-d que vous devez les avoir installées au moment de la compilation. .TP .B Écriture: \fIJPEG\fP, \fIPNG\fP, \fIPostScript\fP, \fIPPM\fP, \fITIFF\fP. .SS Utilisation du glisser-déposer .B Ida est une application motif et elle prend donc en charge le protocole de glisser-déposer de motif dans les deux directions. Le protocole \fBxdnd\fP est aussi pris en charge, mais seulement dans une direction (reception du déposer). .P .BR Ida utilise le bouton du milieu de la souris pour démarrer une opération de glisser-déposer (tel que le guide de motif le suggère). Ceci fonctionne pour la fenêtre principale et les boutons de l'écran de l'explorateur de fichier. .P Les .B applications Motif ne devraient avoir aucune difficulté à dialoguer avec le glisser-déposer .BR "" "d'" "ida" "." Votre pouvez déposer des images dans une fenêtre netscape 4.x -- Ceci implique un certain travail. Mozilla accepte aussi les glisser-déposer. .P L'interopérabilité avec .B gnome / gtk est bonne. Je peux déplacer des fichiers .BR "" "d'" "ida" vers .BR eeyes et vice versa sans problème. Les déplacement depuis .BR gmc vers .BR ida fonctionnent aussi très bien. .P L'interopérabilité avec .B KDE est mauvaise. Le copier-coller marche la plupart du temps, mais pas souvent le glisser-déposer. La fonction de sélection X11 du Qt toolkit a une conception légérement boguée et peu économe. Fondamentalement, les trolleurs ne comprennent pas le but de la cible TARGETS et violent les spécifications ICCCM en l'ignorant. \# \# .SH "VOIR AUSSI" .BR xwd (1) \# \# .SH TRADUCTEUR Stéphane Aulery .BR \# \# .SH AUTEUR Gerd Hoffmann .BR \# \# .SH COPYRIGHT Copyright (c) 2002-2012 Gerd Hoffmann .P 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. .P 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. .P 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., 675 Mass Ave, Cambridge, MA 02139, USA. fbi-2.10/fbgs.man0000644000175000017500000000504612506525033011750 0ustar jmmjmm.TH FBGS 1 "(c) 1999\-2012 Gerd Hoffmann" "FBGS 2.09" "PostScript/pdf viewer for the linux framebuffer console" \# \# .SH NAME fbgs \- Poor man's PostScript/pdf viewer for the linux framebuffer console. \# \# .SH SYNOPSIS \fBfbgs\fP\ [\fB\-l\fP|\fB\-xl\fP|\fB\-xxl\fP|\fB\-r\fP \fIn\fP]\ [\fB\-c\fP]\ [\fB\-b\fP]\ [\fB\-p\fP\ \fIpassword\fP]\ [\fB\--fp\fP\ \fInumber\fP]\ [\fB\--lp\fP\ \fInumber\fP]\ [\fIfbi\ options\fP]\ \fIfile\fP \# \# .SH DESCRIPTION .BR Fbgs is a simple wrapper script which takes a \fIPostScript\fP (PS) or \fIPortable Document Format\fP (PDF) file as input, renders the pages using .BR gs (1) \- GhostScript \- into a temporary directory and finally calls .BR fbi (1) to display them. .SH OPTIONS .BR Fbgs understands all .BR fbi (1) options (they are passed through), except: store, list, text, (no)comments, e, (no)edit, (no)backup, (no)preserve, (no)readahead, cachemem, blend. .P Additionally you can specify: .TP .B -h, --help Print usage info (overwrites fbi option). .TP .B -b, --bell Emit a beep when the document is ready. .TP .B -c, --color To render the pages in color (default is N&B). .TP .B -l To get the pages rendered with 100 dpi (default is 75). .TP .B -xl To get the pages rendered with 120 dpi. .TP .B -xxl To get the pages rendered with 150 dpi. .TP .BI "-r" "\ n" ", --resolution" "\ n" To get the pages rendered with \fIn\fP dpi (overwrites fbi option). .TP .BI "-fp" "\ number" ", --firstpage" "\ number" Begins interpreting on the designated page of the document. .TP .BI "-lp" "\ number" ", --lastpage" "\ number" Stops interpreting after the designated page of the document. .TP .BI "-p" "\ password" ", --password" "\ password" You can use this option if your PDF file requires a \fIpassword\fP. \# \# .SH "SEE ALSO" .BR fbi (1), .BR gs (1) \# \# .SH AUTHOR Gerd Hoffmann .BR \# \# .SH COPYRIGHT Copyright (c) 1999-2012 Gerd Hoffmann .P 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. .P 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. .P 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., 675 Mass Ave, Cambridge, MA 02139, USA. fbi-2.10/filter.c0000644000175000017500000002731312506525033011764 0ustar jmmjmm#include #include #include #include #include "readers.h" #include "filter.h" int debug = 0; /* ----------------------------------------------------------------------- */ static void op_grayscale(struct ida_image *src, struct ida_rect *rect, unsigned char *dst, int line, void *data) { unsigned char *scanline; int i,g; scanline = src->data + line * src->i.width * 3; memcpy(dst,scanline,src->i.width * 3); if (line < rect->y1 || line >= rect->y2) return; dst += 3*rect->x1; scanline += 3*rect->x1; for (i = rect->x1; i < rect->x2; i++) { g = (scanline[0]*30 + scanline[1]*59+scanline[2]*11)/100; dst[0] = g; dst[1] = g; dst[2] = g; scanline += 3; dst += 3; } } /* ----------------------------------------------------------------------- */ struct op_3x3_handle { struct op_3x3_parm filter; int *linebuf; }; static void* op_3x3_init(struct ida_image *src, struct ida_rect *rect, struct ida_image_info *i, void *parm) { struct op_3x3_parm *args = parm; struct op_3x3_handle *h; h = malloc(sizeof(*h)); memcpy(&h->filter,args,sizeof(*args)); h->linebuf = malloc(sizeof(int)*3*(src->i.width)); *i = src->i; return h; } static int inline op_3x3_calc_pixel(struct op_3x3_parm *p, unsigned char *s1, unsigned char *s2, unsigned char *s3) { int val = 0; val += p->f1[0] * s1[0]; val += p->f1[1] * s1[3]; val += p->f1[2] * s1[6]; val += p->f2[0] * s2[0]; val += p->f2[1] * s2[3]; val += p->f2[2] * s2[6]; val += p->f3[0] * s3[0]; val += p->f3[1] * s3[3]; val += p->f3[2] * s3[6]; if (p->mul && p->div) val = val * p->mul / p->div; val += p->add; return val; } static void op_3x3_calc_line(struct ida_image *src, struct ida_rect *rect, int *dst, unsigned int line, struct op_3x3_parm *p) { unsigned char b1[9],b2[9],b3[9]; unsigned char *s1,*s2,*s3; unsigned int i,left,right; s1 = src->data + (line-1) * src->i.width * 3; s2 = src->data + line * src->i.width * 3; s3 = src->data + (line+1) * src->i.width * 3; if (0 == line) s1 = src->data + line * src->i.width * 3; if (src->i.height-1 == line) s3 = src->data + line * src->i.width * 3; left = rect->x1; right = rect->x2; if (0 == left) { /* left border special case: dup first col */ memcpy(b1,s1,3); memcpy(b2,s2,3); memcpy(b3,s3,3); memcpy(b1+3,s1,6); memcpy(b2+3,s2,6); memcpy(b3+3,s3,6); dst[0] = op_3x3_calc_pixel(p,b1,b2,b3); dst[1] = op_3x3_calc_pixel(p,b1+1,b2+1,b3+1); dst[2] = op_3x3_calc_pixel(p,b1+2,b2+2,b3+2); left++; } if (src->i.width == right) { /* right border */ memcpy(b1,s1+src->i.width*3-6,6); memcpy(b2,s2+src->i.width*3-6,6); memcpy(b3,s3+src->i.width*3-6,6); memcpy(b1+3,s1+src->i.width*3-3,3); memcpy(b2+3,s2+src->i.width*3-3,3); memcpy(b3+3,s3+src->i.width*3-3,3); dst[src->i.width*3-3] = op_3x3_calc_pixel(p,b1,b2,b3); dst[src->i.width*3-2] = op_3x3_calc_pixel(p,b1+1,b2+1,b3+1); dst[src->i.width*3-1] = op_3x3_calc_pixel(p,b1+2,b2+2,b3+2); right--; } dst += 3*left; s1 += 3*(left-1); s2 += 3*(left-1); s3 += 3*(left-1); for (i = left; i < right; i++) { dst[0] = op_3x3_calc_pixel(p,s1++,s2++,s3++); dst[1] = op_3x3_calc_pixel(p,s1++,s2++,s3++); dst[2] = op_3x3_calc_pixel(p,s1++,s2++,s3++); dst += 3; } } static void op_3x3_clip_line(unsigned char *dst, int *src, int left, int right) { int i,val; src += left*3; dst += left*3; for (i = left*3; i < right*3; i++) { val = *(src++); if (val < 0) val = 0; if (val > 255) val = 255; *(dst++) = val; } } static void op_3x3_work(struct ida_image *src, struct ida_rect *rect, unsigned char *dst, int line, void *data) { struct op_3x3_handle *h = data; unsigned char *scanline; scanline = src->data + line * src->i.width * 3; memcpy(dst,scanline,src->i.width * 3); if (line < rect->y1 || line >= rect->y2) return; op_3x3_calc_line(src,rect,h->linebuf,line,&h->filter); op_3x3_clip_line(dst,h->linebuf,rect->x1,rect->x2); } static void op_3x3_free(void *data) { struct op_3x3_handle *h = data; free(h->linebuf); free(h); } /* ----------------------------------------------------------------------- */ struct op_sharpe_handle { int factor; int *linebuf; }; static void* op_sharpe_init(struct ida_image *src, struct ida_rect *rect, struct ida_image_info *i, void *parm) { struct op_sharpe_parm *args = parm; struct op_sharpe_handle *h; h = malloc(sizeof(*h)); h->factor = args->factor; h->linebuf = malloc(sizeof(int)*3*(src->i.width)); *i = src->i; return h; } static void op_sharpe_work(struct ida_image *src, struct ida_rect *rect, unsigned char *dst, int line, void *data) { static struct op_3x3_parm laplace = { f1: { 1, 1, 1 }, f2: { 1, -8, 1 }, f3: { 1, 1, 1 }, }; struct op_sharpe_handle *h = data; unsigned char *scanline; int i; scanline = src->data + line * src->i.width * 3; memcpy(dst,scanline,src->i.width * 3); if (line < rect->y1 || line >= rect->y2) return; op_3x3_calc_line(src,rect,h->linebuf,line,&laplace); for (i = rect->x1*3; i < rect->x2*3; i++) h->linebuf[i] = scanline[i] - h->linebuf[i] * h->factor / 256; op_3x3_clip_line(dst,h->linebuf,rect->x1,rect->x2); } static void op_sharpe_free(void *data) { struct op_sharpe_handle *h = data; free(h->linebuf); free(h); } /* ----------------------------------------------------------------------- */ struct op_resize_state { float xscale,yscale,inleft; float *rowbuf; unsigned int width,height,srcrow; }; static void* op_resize_init(struct ida_image *src, struct ida_rect *rect, struct ida_image_info *i, void *parm) { struct op_resize_parm *args = parm; struct op_resize_state *h; h = malloc(sizeof(*h)); h->width = args->width; h->height = args->height; h->xscale = (float)args->width/src->i.width; h->yscale = (float)args->height/src->i.height; h->rowbuf = malloc(src->i.width * 3 * sizeof(float)); h->srcrow = 0; h->inleft = 1; *i = src->i; i->width = args->width; i->height = args->height; i->dpi = args->dpi; return h; } static void op_resize_work(struct ida_image *src, struct ida_rect *rect, unsigned char *dst, int line, void *data) { struct op_resize_state *h = data; float outleft,left,weight,d0,d1,d2; unsigned char *csrcline; float *fsrcline; unsigned int i,sx,dx; /* scale y */ memset(h->rowbuf, 0, src->i.width * 3 * sizeof(float)); outleft = 1/h->yscale; while (outleft > 0 && h->srcrow < src->i.height) { if (outleft < h->inleft) { weight = outleft * h->yscale; h->inleft -= outleft; outleft = 0; } else { weight = h->inleft * h->yscale; outleft -= h->inleft; h->inleft = 0; } #if 0 if (debug) fprintf(stderr,"y: %6.2f%%: %d/%d => %d/%d\n", weight*100,h->srcrow,src->height,line,h->height); #endif csrcline = src->data + h->srcrow * src->i.width * 3; for (i = 0; i < src->i.width * 3; i++) h->rowbuf[i] += (float)csrcline[i] * weight; if (0 == h->inleft) { h->inleft = 1; h->srcrow++; } } /* scale x */ left = 1; fsrcline = h->rowbuf; for (sx = 0, dx = 0; dx < h->width; dx++) { d0 = d1 = d2 = 0; outleft = 1/h->xscale; while (outleft > 0 && dx < h->width && sx < src->i.width) { if (outleft < left) { weight = outleft * h->xscale; left -= outleft; outleft = 0; } else { weight = left * h->xscale; outleft -= left; left = 0; } #if 0 if (debug) fprintf(stderr," x: %6.2f%%: %d/%d => %d/%d\n", weight*100,sx,src->width,dx,h->width); #endif d0 += fsrcline[3*sx+0] * weight; d1 += fsrcline[3*sx+1] * weight; d2 += fsrcline[3*sx+2] * weight; if (0 == left) { left = 1; sx++; } } dst[0] = d0; dst[1] = d1; dst[2] = d2; dst += 3; } } static void op_resize_done(void *data) { struct op_resize_state *h = data; free(h->rowbuf); free(h); } /* ----------------------------------------------------------------------- */ struct op_rotate_state { float angle,sina,cosa; struct ida_rect calc; int cx,cy; }; static void* op_rotate_init(struct ida_image *src, struct ida_rect *rect, struct ida_image_info *i, void *parm) { struct op_rotate_parm *args = parm; struct op_rotate_state *h; float diag; h = malloc(sizeof(*h)); h->angle = args->angle * 2 * M_PI / 360; h->sina = sin(h->angle); h->cosa = cos(h->angle); h->cx = (rect->x2 - rect->x1) / 2 + rect->x1; h->cy = (rect->y2 - rect->y1) / 2 + rect->y1; /* the area we have to process (worst case: 45) */ diag = sqrt((rect->x2 - rect->x1)*(rect->x2 - rect->x1) + (rect->y2 - rect->y1)*(rect->y2 - rect->y1))/2; h->calc.x1 = h->cx - diag; h->calc.x2 = h->cx + diag; h->calc.y1 = h->cy - diag; h->calc.y2 = h->cy + diag; if (h->calc.x1 < 0) h->calc.x1 = 0; if (h->calc.x2 > src->i.width) h->calc.x2 = src->i.width; if (h->calc.y1 < 0) h->calc.y1 = 0; if (h->calc.y2 > src->i.height) h->calc.y2 = src->i.height; *i = src->i; return h; } static inline unsigned char* op_rotate_getpixel(struct ida_image *src, struct ida_rect *rect, int sx, int sy, int dx, int dy) { static unsigned char black[] = { 0, 0, 0}; if (sx < rect->x1 || sx >= rect->x2 || sy < rect->y1 || sy >= rect->y2) { if (dx < rect->x1 || dx >= rect->x2 || dy < rect->y1 || dy >= rect->y2) return src->data + dy * src->i.width * 3 + dx * 3; return black; } return src->data + sy * src->i.width * 3 + sx * 3; } static void op_rotate_work(struct ida_image *src, struct ida_rect *rect, unsigned char *dst, int y, void *data) { struct op_rotate_state *h = data; unsigned char *pix; float fx,fy,w; int x,sx,sy; pix = src->data + y * src->i.width * 3; memcpy(dst,pix,src->i.width * 3); if (y < h->calc.y1 || y >= h->calc.y2) return; dst += 3*h->calc.x1; memset(dst, 0, (h->calc.x2-h->calc.x1) * 3); for (x = h->calc.x1; x < h->calc.x2; x++, dst+=3) { fx = h->cosa * (x - h->cx) - h->sina * (y - h->cy) + h->cx; fy = h->sina * (x - h->cx) + h->cosa * (y - h->cy) + h->cy; sx = (int)fx; sy = (int)fy; if (fx < 0) sx--; if (fy < 0) sy--; fx -= sx; fy -= sy; pix = op_rotate_getpixel(src,rect,sx,sy,x,y); w = (1-fx) * (1-fy); dst[0] += pix[0] * w; dst[1] += pix[1] * w; dst[2] += pix[2] * w; pix = op_rotate_getpixel(src,rect,sx+1,sy,x,y); w = fx * (1-fy); dst[0] += pix[0] * w; dst[1] += pix[1] * w; dst[2] += pix[2] * w; pix = op_rotate_getpixel(src,rect,sx,sy+1,x,y); w = (1-fx) * fy; dst[0] += pix[0] * w; dst[1] += pix[1] * w; dst[2] += pix[2] * w; pix = op_rotate_getpixel(src,rect,sx+1,sy+1,x,y); w = fx * fy; dst[0] += pix[0] * w; dst[1] += pix[1] * w; dst[2] += pix[2] * w; } } static void op_rotate_done(void *data) { struct op_rotate_state *h = data; free(h); } /* ----------------------------------------------------------------------- */ struct ida_op desc_grayscale = { name: "grayscale", init: op_none_init, work: op_grayscale, done: op_none_done, }; struct ida_op desc_3x3 = { name: "3x3", init: op_3x3_init, work: op_3x3_work, done: op_3x3_free, }; struct ida_op desc_sharpe = { name: "sharpe", init: op_sharpe_init, work: op_sharpe_work, done: op_sharpe_free, }; struct ida_op desc_resize = { name: "resize", init: op_resize_init, work: op_resize_work, done: op_resize_done, }; struct ida_op desc_rotate = { name: "rotate", init: op_rotate_init, work: op_rotate_work, done: op_rotate_done, }; fbi-2.10/logo.jpg0000644000175000017500000004113612506525033011774 0ustar jmmjmmJFIF StockenteC     C   " }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?"Y.##,|#]@i.0>}U,~hH?*I+3K⼜~YJޘRr \͂GZo_|[|I泾3Rr\G}?n8cFv@.[[T5f@ _Q-V;+8Ue& dq477_@>*)>xoQEȆecxX5]{ɞv18Lz|-!.gnw?Nylgt%yi˵fia|8Юmol`kIbo?M:o&MQh,Wtn4'<7w"ȅʊR˹Zi'/&nQa ֦'<"֬S;R1x-GPk=:XH |Mmj{6[)gF:8F*:d0GYLVocイ6j8TJcc65WKLK@ isꠀzuzhsIݗ vg>«5o+=7y99@sX$s,rgX;^+m\T(W{h1 DC`aMG]Wm+C=XmrpG_8|tWVOx[ ,9s]O/,h:i}\@cOڤQiʢ iS*lKyˆ%dv 7H֮|uÝoP[`bJ៊OGnRN3?ڬdch֩vίO>Uωu1fY NGDе j_)#}k4:&H"URH@l:8_9hFX">|'}6xX1xmʶ8'xzJu-O&'mbeaBĊd^VVE.+ݎwgoa]j F~F?u@&=_>۳8Oza:/ac-ă0ګߝ;sLť^Z#o;V.Zizy{S% ԏ0n_@z^6Wi@b3zUi-J`G7#%qG)$ڙu#$I ҽo-;}qyogRZ¨evPx/˜jkw?r)żEKA Qq]s'\IQu-58l~$ẕ`F#+ F}gZV 7N`014ݘ'|u▃n';ȧp>ؽe-ZHyXr+u-.HHY+1]Ly,{w=[Xcu~w5rY MRuy-j752 Mh`owor&g>s=^+$ & ~—v:dhMe"幕{dtŷWR=+mt-lݼC3Ҷ|M=6rZʼİ-11`@w=? )NJYk&N2ؑ3=?:dmFa6mn3w=kmuۭjmLdMݮe2M淏O͊9Qٯ-A}d$By'_Lt >PRPaٴd-srβ'ұtJh_ fD+Yӭ)mjޟ5t Y[XƸ_6]+ͯﮮ%h!%nxWP}6XGt`IM!;Zn ⌗bh,Jҩ|l)aA2C^JmN#1xĨ!Yo{ {"%ǿ6PF Jh:5H%`@|֮-\!\\E_|q\5cUXFO^{P)KI+k;[e1qy h'^էxkWy/ ~`Ks-ͪAP=8Y$/#k#8c=J]ZjR v4q\nVUP #4d23GҼ⦣.;[~:%FG -Jk=d_:Xst.R8cm?RQϡ^\k[2rDhY ?cGFK/'OhKfy)&r g@3(u#Xd@ϖ|iR3Mc&{p$FFI GO/d4m*QnMst*r('9?zUGzܗ6I-,k {VN=viduA2?eĨ͉mF;4?:Aso7%";oP1_Fx+‹+` 5@?O c%4*ɼ$ yG=bH>:xMŻ{˖M۷:g?֬6́;+9e?R]3hMNsh7?ʺmS]Θe'H>=gMwda%qT²u;BHZ4,p̧ѵ#@Ă4ץyĘnR:ԣ``)KB[dZYK3\(}u lչo0σTM0 qF= Ouq($t]LEM,w1?NT}qHVԮf,c uKUkf&G/}u$nzΕ{dF_LLG#LO&S9VzxG$k&Ӻ㋊u*MkpyaulM%H5}t˻kk9M2P 7N,i>_/fcTJj|s3M(ڰ)g'vγ᮷oy_XiϬG1$,N?*V-Mݨܠu#~I{wwӒ{\ms⯈0kнdRN=H7Лzw.7V!]q\TԺd g5?K(fVa\L~4i+v2?ۊL1 ~-qvncG.z7\.i-mlrHNGwoC0O4}4/G#yW SK8,|2 v,P2>b/'3DD< ֙AAmT{ʻ-)t_]_LZ@}XRA ?+rQԄ`{k,mn4*O3bDM̤zP49mks>4*PYnLX9$nqyLvTRL|͝| ş_H\]K y1OX]GA4JGuÖS.0瓓I71#.i19nVEq'jExW]-pښIq;^ xa{_:[]{%yDGm̫" C!N9\7`k>7u9>,։Ń$(|3:8*1^fz#x{RA4Ig O&;]2W.<N9#*ޝ>)[H-@"ĕ xP݉c}3aWnVƝV#Cn9,DdKnsА:J)3v A͢ʲ,;n^/y\Gqr%2Z@jZPA]I'9vQܑz{Q`f5)] In$ys+yFI =seK`($Y~ ]1#G,䓏l7ɪ۱]MT`W/X\\#lKEI9-k7$q<d-nVh6=֡x`s!Ȯ_R!!%`R3ԀjZzIq? Jl/qb.XnAgW;.u=ӛ4+j+摒? w%Q% *o ?bm@O:I!]/u K;c }ֹ -@K~2)|It 7FnTqv=+!y{wKL Ȯ;o}{X)3%W]\k>xlˍ 1W VLp@^8zc.sX:% 1"xHl/a;)t0^ ~ԴV${dײ3NaѬi'ch9Z4.^\ZڳƟ;O,J_r? Iomduּ6mK0)=,Z M4ȷouˏnC}HdHU JoM6-BG dR0985$,-H˓Ӟd;b1Q;<.3P֣ԈGↀyFˬjzj3*Ǡ<±>/OI;;ǝ֞+;CjeFYm.B>[A[2;YXgs[iIN UǻnӃU~_RZcVr.~fRKit6j}O7Zin+@ɷڹ; ֲ5~ ~d5s2'sG\Y%´ {.r@WR1^޺F= pjmp[ǜ.ɩ3qkY^H8fa흵cK,.N;p6 {؂J}sK;,jȻC#2wTc3_Akmom,y$Wc*zBkCYӄO6kzd6#h N f 20>uwihz?gi JdPI+5OCֵ}R[K-%52M+^E7[fMn}OZe9c?*u6lF4kD.sw]^I쁇˷3*qN4KrW]Kgqܳ!R؎AW^xSҪjmu>pI0z_/5xLYo'5Z bE9 8 :bL14> Bdɯ&|aslm߈4Q)!Zz֡ 7݅s,q֒|(*6[B6Hax(qƴEw@#h k!X'ȧ^7~10iԎq--2X`e^/:/u"W"#Hx?CXQ"Kpby/OړƚV%iw t(I =*[ J/Y+u8 ~?A1UrLBWr=&NFID,qV.m۹^u?7ԙoȐ>fVTQ7tD <'Vܲ3?:mZ|bdv$lz/f ɆR?(WŻ XJ%mƒ7VEuSPK}c-þKmƲFSivKh,WUGse^$;XKOZo:wu$Eo1t^~b+[KeVν`D0 g$qIWf^F\Ć1 UVKdx߆g^z6 χ.ly5Zf~;18+qKZafPGVj%ί]dWl&oT`pk{mubJoq+g^);{xT sB }` c'N}:MR1ƸܧِtOG+WsA \vm-E* ZZV@t=T0Z`#<ֺ Mq߽(fƤ8ˆ`SюrsPJ3Ԋ9ȦSRB;]j q!p>s:zyv- gx]Mx"[XyӱH>|cO ?a?%Usԗ*:fXҗHMP##D.Km"6hᏍ WInʖfsNG cQ||ţ)Fҳ2yY~:Of. yF]S09=bW3o⢕՝cUOQ|5Z H<| ڼwlҾ!{xFUnR{cM|o&74+rٱǖ7+P_U(uIɲ8fLgҫJx t%yߎsީGqo5 u\{h~xXemF4#I"mg,b;G S㶲M 6㯿Z紝}?y> qu2H#{w?a'wӡ#W񾛨Ir%mu>ּG÷zA-wzgk=LKU| Kp!,qr1>3f9>!it=V;aļ?&4rW g}{!uWj:|Yw%i[g?UC Kd+cÂY@5 FrwhO侟[z 15Dr(gph *x;Xb*Ks.Ig@g<8{Z{Z,${W[j*O%լR {r*rI]oFV=>{s,$Ѩ`_J߲hUND$qtFb!s&~MZS/O : $yV?(q<}j-Z7g9:>=LFoq@S,]=e s֘B$|jŀ )JƁGTm(WmT\cҮ)޹=vZQ%kx[>^yךIr7Wi\琛]Pga>#:e*Z|O[~VuYq>բlՓQvYZ {{WFu@#\gU% ¡/wu>.?&-^O4<'OҌuHr_GTǎ~*ji-ŭP;\솥Y*6aT 䯵{=At.QIxuZG[ܵ44пgAiL%$Myz<叠a_,Ae j>!j~SZM0MvD}Xׯ|D<->ImI@ev#~QߟJ_ok⾢ڥˋTZY!\sG;aVR| 54'.&!&U.$$'?Pi-e}Y},=&8#Ig$YUs:=Ɓjd[U5jL㌛}liᄊzZlOogI+: 3r@]O4/$6lDISSmogk:ZG#"?BkQcXT"[%DT$>IǠBs0A88EVm>U_ְK KO9=|_ڳ–\2Jӧ|/ACO>*yU}˭|BmȽi_Cs_~j R2yeoF^c#?NkW-?8{'iPʦ!5)[ˠ-$vO,z{Q[iW"շiW6%u)O|W9/O$8[RMBAoq!\?tD"֒;+i"4 I5>w|?P\]wOM aٮDKy-,Fr$_N[aIƿu@ ׁEK_:Q2ȣp^KH't29OAZlTU:+yYQgwAZʴצY/cqZ: ^>mI+ICҬBmHzt5BB>M.-H۾ ,j]b23Hі={oΙ"(Eϵ4wR^aqTc?Zbz{UcMIp3Vbӵ85pZV4 x55PKc|1 s^'7/o<֌O!*~Zk=&MR`6uS؏pFkxOPn%ETb$v&R%.9f ۪zKQodD`L˟JfY{Vn [Vf(;}~?{`HD0=j?xI莤) e+ fP]J} nhyHW]ែm:|^Hr_< 6VjA,'`U+8{O5S^*O(IopvCV͎.:`ۅ pp)Mrs+fO,rJb犯 d&1.{/*<hc{Z)wPMK c~(:2=봚В>oz"u($4r@YUp1THYtʱ:7Dwڄdv|YcXj$1pO}1Q;a&{֓M+XZbK~]kb5ÎE|ySM$\X)Mn<;c—k5WMJfc2ܨ>ǿ/upU110${w5]NJ#HrI%I\zSG5mI; ԣ:qT%=jYNYF:Ui(Isegd {m#{ikmSVTla,kʶf9,W2|'קKS|t4;%F\ Rnd AlC~u<0ӟD&p R}>Z9I xg5Ң&ԝw<vֽ[XXNGB9RM] Qч>*.,9*B+gitkRI B;EsS]m6sgW $hfo,ӽ:Ty+q[ZgTmݶO b*?3^oZGxc!FzǠBnB?Gzbh̢UW?*یƻ##sR\4PLVEֲl_R9&('k#VORM$x z ">Zu {XSjU=8uliS,8Ң0rIA.# VHEU8K,EI.oyNc)sPɞ֯Ao)Z,nw rk*쥳|svJ)w|XŻ^o^@ͻ* aCuo 9%6R*x4EdXN8fޔ?S-~QScO>*RHVg/#&7&ϖ2yȮvI< UoԏƱq}MOcb\3})WY(LȒR@/zM Wֹؓ{THCȬ{MOֺ}29==^\ysL13d3O*3zWWS޹:=YK=e-eځO|fn_ơIJ֞XlCV>_v#[, rF*A#[mci}ei]4]c`!^Nw sx_wŪkW Mj}h뎇5TVRТU;╺jkW Ft*7kjwI=iZkjXiWR6698Mݘz~xWִNM{xt6[thc] K#+sb+ͼ h 5/,^=2kg#8ڹRk]hS[/M[I{.Z;=VWv{Zwc.ﰊaJ\pd.|VS7O77ZS'@ z]oJkZmLj++m0(kEBvi*NNAU~kcuW34:]h|@,kkV/cm[tvPT}/VG~3ô;y2E!D-GV8hLۣ>^KӾ$h3ͷ}ޡᤶHJB/DH* Ӟ+G X^5-yg ӾTqU7Ietxj1pwۯ_}b;I~kā<7!Kץɶ<%ZAyS1ɰ񇂿!nӦjz۴86SJ.r223W ʺo-U]Eɥ^;O??_ɣQ2v? 3J?U^Xw=*ʀ/ ܤ7MíYIWNKfI&lZ7I)b1DYF1OnڼҭXytem׏^>}O{k g#ir$wcw? =jV#8laMCG[)k.1ɕXgo#:v֚e6l6 m AOUT+ҝHI=,]4*}&K,^yUR,,@g/d :'LR|1*_7fx]vvq\>#Ys׋Dկn䶷{mbt*T`ԃnn2Jٻ7ma4VoKnߡLh5NXd*~=+ c;=/ſ>nbζ7K[Ҏ2!ʋZm;6a)\Ѭm=^j1gMkx g'Nܑۚ+xWSѤn4ж莩LV d0܆ ͊m?gqKi$uqy4hc` I׫;yyۢ{ ~IY{t??++keeˣK%:|R~0Ҫ5bJ_J(j49]Xmfiy(. #define POINTER_NORMAL 0 #define POINTER_BUSY 1 #define POINTER_PICK 2 #define RUBBER_NEW 3 #define RUBBER_MOVE 4 #define RUBBER_X1 5 #define RUBBER_Y1 6 #define RUBBER_X2 7 #define RUBBER_Y2 8 #define POINTER_COUNT 9 extern Cursor ptrs[]; /* ----------------------------------------------------------------------- */ typedef void (*viewer_pick_cb)(int x, int y, unsigned char *pix, XtPointer data); struct ida_viewer { /* x11 stuff */ Widget widget; GC wgc; XtIntervalId timer; /* image data */ struct ida_image img; struct ida_image undo; char *file; /* view data */ int zoom; unsigned int scrwidth, scrheight; XImage *ximage; void *ximage_shm; unsigned char *rgb_line; unsigned char *dither_line; unsigned char *preview_line; /* marked rectangle */ struct ida_rect current; int marked,state; int last_x,last_y; unsigned long mask; /* pixel picker */ viewer_pick_cb pick_cb; XtPointer pick_data; /* workproc state */ XtWorkProcId wproc; unsigned int line; unsigned int steps; /* image loader */ unsigned int load_line; void (*load_read)(unsigned char *dst, unsigned int line, void *data); void (*load_done)(void *data); void *load_data; /* image operation */ struct ida_image op_src; struct ida_rect op_rect; unsigned int op_line; unsigned int op_preview; void (*op_work)(struct ida_image *src, struct ida_rect *rect, unsigned char *dst, int line, void *data); void (*op_done)(void *data); void *op_data; }; /* ----------------------------------------------------------------------- */ Pixmap image_to_pixmap(struct ida_image *img); /* ----------------------------------------------------------------------- */ struct ida_viewer* viewer_init(Widget widget); int viewer_loader_start(struct ida_viewer *ida, struct ida_loader *loader, FILE *fp, char *filename, unsigned int page); int viewer_loadimage(struct ida_viewer *ida, char *filename, unsigned int page); int viewer_setimage(struct ida_viewer *ida, struct ida_image *img, char *name); void viewer_autozoom(struct ida_viewer *ida); void viewer_setzoom(struct ida_viewer *ida, int zoom); int viewer_i2s(int zoom, int val); int viewer_undo(struct ida_viewer *ida); int viewer_start_op(struct ida_viewer *ida, struct ida_op *op, void *parm); int viewer_start_preview(struct ida_viewer *ida, struct ida_op *op, void *parm); int viewer_cancel_preview(struct ida_viewer *ida); void viewer_pick(struct ida_viewer *ida, viewer_pick_cb cb, XtPointer data); void viewer_unpick(struct ida_viewer *ida); fbi-2.10/man.h0000644000175000017500000000026412506525033011253 0ustar jmmjmmvoid man(char *page); void man_cb(Widget widget, XtPointer clientdata, XtPointer call_data); void man_action(Widget widget, XEvent *event, String *params, Cardinal *num_params); fbi-2.10/fbiconfig.c0000644000175000017500000001072412506525033012423 0ustar jmmjmm#include #include #include #include #include #include #include "fbiconfig.h" /* ------------------------------------------------------------------------ */ struct cfg_cmdline fbi_cmd[] = { { .letter = 'h', .cmdline = "help", .option = { O_HELP }, .value = "1", .desc = "print this help text", },{ .letter = 'V', .cmdline = "version", .option = { O_VERSION }, .value = "1", .desc = "print fbi version number", },{ .cmdline = "store", .option = { O_WRITECONF }, .value = "1", .desc = "write cmd line args to config file", },{ .letter = 'l', .cmdline = "list", .option = { O_FILE_LIST }, .needsarg = 1, .desc = "read image filelist from file ", },{ .letter = 'P', .cmdline = "text", .option = { O_TEXT_MODE }, .value = "1", .desc = "switch into text reading mode", },{ .letter = 'a', .cmdline = "autozoom", .option = { O_AUTO_ZOOM }, .value = "1", .desc = "automagically pick useful zoom factor", },{ /* end of list */ } }; struct cfg_cmdline fbi_cfg[] = { { .cmdline = "autoup", .option = { O_AUTO_UP }, .yesno = 1, .desc = " like the above, but upscale only", },{ .cmdline = "autodown", .option = { O_AUTO_DOWN }, .yesno = 1, .desc = " like the above, but downscale only", },{ .cmdline = "fitwidth", .option = { O_FIT_WIDTH }, .yesno = 1, .desc = " use width only for autoscaling", },{ .letter = 'v', .cmdline = "verbose", .option = { O_VERBOSE }, .yesno = 1, .desc = "show filenames all the time", },{ .letter = 'u', .cmdline = "random", .option = { O_RANDOM }, .yesno = 1, .desc = "show files in a random order", },{ .letter = '1', .cmdline = "once", .option = { O_ONCE }, .yesno = 1, .desc = "don't loop (for use with -t)", },{ .cmdline = "comments", .option = { O_COMMENTS }, .yesno = 1, .desc = "display image comments", },{ .letter = 'e', .cmdline = "edit", .option = { O_EDIT }, .yesno = 1, .desc = "enable editing commands (see man page)", },{ .cmdline = "backup", .option = { O_BACKUP }, .yesno = 1, .desc = " create backup files when editing", },{ .cmdline = "preserve", .option = { O_PRESERVE }, .yesno = 1, .desc = " preserve timestamps when editing", },{ .cmdline = "readahead", .option = { O_READ_AHEAD }, .yesno = 1, .desc = "read ahead images into cache", },{ .cmdline = "cachemem", .option = { O_CACHE_MEM }, .needsarg = 1, .desc = "image cache size in megabytes", },{ .cmdline = "blend", .option = { O_BLEND_MSECS }, .needsarg = 1, .desc = "image blend time in miliseconds", },{ .letter = 'T', .cmdline = "vt", .option = { O_VT }, .needsarg = 1, .desc = "start on virtual console ", },{ .letter = 's', .cmdline = "scroll", .option = { O_SCROLL }, .needsarg = 1, .desc = "scroll image by pixels", },{ .letter = 't', .cmdline = "timeout", .option = { O_TIMEOUT }, .needsarg = 1, .desc = "load next image after sec without user input", },{ .letter = 'r', .cmdline = "resolution", .option = { O_PCD_RES }, .needsarg = 1, .desc = "pick PhotoCD resolution (1..5)", },{ .letter = 'g', .cmdline = "gamma", .option = { O_GAMMA }, .needsarg = 1, .desc = "set display gamma (doesn't work on all hardware)", },{ .letter = 'f', .cmdline = "font", .option = { O_FONT }, .needsarg = 1, .desc = "use font (anything fontconfig accepts)", },{ .letter = 'd', .cmdline = "device", .option = { O_DEVICE }, .needsarg = 1, .desc = "use framebuffer device ", },{ .letter = 'm', .cmdline = "mode", .option = { O_VIDEO_MODE }, .needsarg = 1, .desc = "use video mode (from /etc/fb.modes)", },{ /* end of list */ } }; /* ------------------------------------------------------------------------ */ static char *fbi_config = NULL; static void init_config(void) { char *home; home = getenv("HOME"); if (NULL == home) return; fbi_config = malloc(strlen(home) + 16); sprintf(fbi_config,"%s/.fbirc", home); } void fbi_read_config(void) { init_config(); if (fbi_config) cfg_parse_file("config", fbi_config); } void fbi_write_config(void) { if (fbi_config) cfg_write_file("config", fbi_config); } fbi-2.10/readers.c0000644000175000017500000000513612506525033012123 0ustar jmmjmm#include #include #include #include #include "readers.h" /* ----------------------------------------------------------------------- */ void load_bits_lsb(unsigned char *dst, unsigned char *src, int width, int on, int off) { int i,mask,bit; for (i = 0; i < width; i++) { mask = 1 << (i & 0x07); bit = src[i>>3] & mask; dst[0] = bit ? on : off; dst[1] = bit ? on : off; dst[2] = bit ? on : off; dst += 3; } } void load_bits_msb(unsigned char *dst, unsigned char *src, int width, int on, int off) { int i,mask,bit; for (i = 0; i < width; i++) { mask = 1 << (7 - (i & 0x07)); bit = src[i>>3] & mask; dst[0] = bit ? on : off; dst[1] = bit ? on : off; dst[2] = bit ? on : off; dst += 3; } } void load_gray(unsigned char *dst, unsigned char *src, int width) { int i; for (i = 0; i < width; i++) { dst[0] = src[0]; dst[1] = src[0]; dst[2] = src[0]; dst += 3; src += 1; } } void load_graya(unsigned char *dst, unsigned char *src, int width) { int i; for (i = 0; i < width; i++) { dst[0] = src[0]; dst[1] = src[0]; dst[2] = src[0]; dst += 3; src += 2; } } void load_rgba(unsigned char *dst, unsigned char *src, int width) { int i; for (i = 0; i < width; i++) { dst[0] = src[0]; dst[1] = src[1]; dst[2] = src[2]; dst += 3; src += 4; } } /* ----------------------------------------------------------------------- */ int load_add_extra(struct ida_image_info *info, enum ida_extype type, unsigned char *data, unsigned int size) { struct ida_extra *extra; extra = malloc(sizeof(*extra)); if (NULL == extra) return -1; memset(extra,0,sizeof(*extra)); extra->data = malloc(size); if (NULL == extra->data) { free(extra); return -1; } extra->type = type; extra->size = size; memcpy(extra->data,data,size); extra->next = info->extra; info->extra = extra; return 0; }; struct ida_extra* load_find_extra(struct ida_image_info *info, enum ida_extype type) { struct ida_extra *extra; for (extra = info->extra; NULL != extra; extra = extra->next) if (type == extra->type) return extra; return NULL; } int load_free_extras(struct ida_image_info *info) { struct ida_extra *next; while (NULL != info->extra) { next = info->extra->next; free(info->extra->data); free(info->extra); info->extra = next; } return 0; } /* ----------------------------------------------------------------------- */ LIST_HEAD(loaders); void load_register(struct ida_loader *loader) { list_add_tail(&loader->list, &loaders); } fbi-2.10/dither.h0000644000175000017500000000036712506525033011763 0ustar jmmjmm extern void (*dither_line)(unsigned char *, unsigned char *, int, int); void init_dither(int, int, int, int); void dither_line_color(unsigned char *, unsigned char *, int, int); void dither_line_gray(unsigned char *, unsigned char *, int, int);